commit 28911d3fa6479881a284bfde4d5777bb92a77560 Author: xuqm Date: Thu Jul 9 11:54:49 2026 +0800 initial: split from lawless main repo diff --git a/api/openapi.yaml b/api/openapi.yaml new file mode 100644 index 0000000..24f3d70 --- /dev/null +++ b/api/openapi.yaml @@ -0,0 +1,2234 @@ +openapi: 3.0.0 +info: + title: 洪荒大陆挂机手游 API + description: 基于 TDD-05 的 RESTful 接口定义(OpenAPI 3.0) + version: 1.0.0 + contact: + name: 洪荒大陆服务端团队 +servers: + - url: https://api.honghuang.example.com + description: 生产网关 + - url: https://api-test.honghuang.example.com + description: 测试网关 + +security: + - bearerAuth: [] + +paths: + /api/v1/auth/register: + post: + tags: [Auth] + summary: 注册(公开) + security: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/RegisterReq' + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/AuthResp' + + /api/v1/auth/login: + post: + tags: [Auth] + summary: 登录(公开) + security: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/LoginReq' + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/AuthResp' + + /api/v1/characters: + post: + tags: [Character] + summary: 创建角色 + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CreateCharacterReq' + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/CharacterResp' + + /api/v1/characters/{character_id}: + get: + tags: [Character] + summary: 获取角色状态 + parameters: + - name: character_id + in: path + required: true + schema: + type: string + format: uuid + - name: with_snapshot + in: query + schema: + type: boolean + default: false + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/CharacterResp' + + /api/v1/characters/{character_id}/realm: + get: + tags: [Realm] + summary: 获取境界进度 + parameters: + - name: character_id + in: path + required: true + schema: + type: string + format: uuid + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/RealmProgressResp' + + /api/v1/characters/{character_id}/realm/breakthrough: + post: + tags: [Realm] + summary: 尝试突破 + parameters: + - name: character_id + in: path + required: true + schema: + type: string + format: uuid + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/BreakthroughReq' + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/BreakthroughResp' + + /api/v1/characters/{character_id}/realm/tribulation: + post: + tags: [Realm] + summary: 发起渡劫 + parameters: + - name: character_id + in: path + required: true + schema: + type: string + format: uuid + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/TribulationReq' + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/TribulationResp' + get: + tags: [Realm] + summary: 查询渡劫结果 + parameters: + - name: character_id + in: path + required: true + schema: + type: string + format: uuid + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/TribulationResp' + + /api/v1/characters/{character_id}/realm/world-break: + post: + tags: [Realm] + summary: 破界(晋级新世界) + parameters: + - name: character_id + in: path + required: true + schema: + type: string + format: uuid + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/WorldBreakReq' + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/WorldBreakResp' + + /api/v1/combats: + post: + tags: [Battle] + summary: 发起战斗 + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/StartCombatReq' + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/CombatResp' + + /api/v1/combats/{battle_id}: + get: + tags: [Battle] + summary: 查询战报 + parameters: + - name: battle_id + in: path + required: true + schema: + type: string + format: uuid + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/BattleReportResp' + + /api/v1/combats/pvp: + post: + tags: [Battle] + summary: PVP 挑战 + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/PvpChallengeReq' + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/CombatResp' + + /api/v1/characters/{character_id}/manuals: + get: + tags: [Manual] + summary: 获取功法列表 + parameters: + - name: character_id + in: path + required: true + schema: + type: string + format: uuid + - name: is_buffing + in: query + schema: + type: boolean + - name: page + in: query + schema: + type: integer + default: 1 + - name: page_size + in: query + schema: + type: integer + default: 20 + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/ManualListResp' + + /api/v1/characters/{character_id}/manuals/{manual_instance_id}/upgrade: + post: + tags: [Manual] + summary: 功法升层 + parameters: + - name: character_id + in: path + required: true + schema: + type: string + format: uuid + - name: manual_instance_id + in: path + required: true + schema: + type: string + format: uuid + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/UpgradeManualReq' + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/ManualResp' + + /api/v1/characters/{character_id}/manuals/{manual_instance_id}/buff: + post: + tags: [Manual] + summary: 设置加持功法 + parameters: + - name: character_id + in: path + required: true + schema: + type: string + format: uuid + - name: manual_instance_id + in: path + required: true + schema: + type: string + format: uuid + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/BuffManualReq' + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/BuffSlotResp' + + /api/v1/characters/{character_id}/skills/learn: + post: + tags: [Skill] + summary: 学习技能 + parameters: + - name: character_id + in: path + required: true + schema: + type: string + format: uuid + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/LearnSkillReq' + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/SkillResp' + + /api/v1/characters/{character_id}/skills/{skill_instance_id}/jade-slip: + post: + tags: [Skill] + summary: 生成功法玉简 + parameters: + - name: character_id + in: path + required: true + schema: + type: string + format: uuid + - name: skill_instance_id + in: path + required: true + schema: + type: string + format: uuid + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/JadeSlipReq' + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/ItemResp' + + /api/v1/characters/{character_id}/currencies: + get: + tags: [Economy] + summary: 获取货币余额 + parameters: + - name: character_id + in: path + required: true + schema: + type: string + format: uuid + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/CurrencyBalancesResp' + + /api/v1/market/orders: + post: + tags: [Economy] + summary: 交易行挂单 + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/MarketOrderReq' + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/MarketOrderResp' + + /api/v1/market/orders/{order_id}: + delete: + tags: [Economy] + summary: 交易行撤单 + parameters: + - name: order_id + in: path + required: true + schema: + type: string + format: uuid + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/MarketOrderResp' + + /api/v1/market/orders/{order_id}/buy: + post: + tags: [Economy] + summary: 交易行购买 + parameters: + - name: order_id + in: path + required: true + schema: + type: string + format: uuid + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/BuyOrderReq' + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/TradeResp' + + /api/v1/auctions: + get: + tags: [Economy] + summary: 查询拍卖列表 + parameters: + - name: world_tier + in: query + schema: + type: integer + - name: auction_type + in: query + schema: + type: string + - name: category + in: query + schema: + type: string + - name: status + in: query + schema: + type: string + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/AuctionListResp' + + /api/v1/auctions/{auction_id}/bids: + post: + tags: [Economy] + summary: 拍卖出价 + parameters: + - name: auction_id + in: path + required: true + schema: + type: string + format: uuid + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/BidReq' + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/BidResp' + + /api/v1/intelligence: + get: + tags: [Economy] + summary: 查询天机阁情报 + parameters: + - name: intel_type + in: query + schema: + type: string + - name: target_world_tier + in: query + schema: + type: integer + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/IntelListResp' + + /api/v1/intelligence/{order_id}/buy: + post: + tags: [Economy] + summary: 购买情报 + parameters: + - name: order_id + in: path + required: true + schema: + type: string + format: uuid + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/IntelBuffResp' + + /api/v1/guilds: + post: + tags: [Social] + summary: 创建组织 + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CreateOrgReq' + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/OrgResp' + + /api/v1/guilds/{guild_id}: + get: + tags: [Social] + summary: 获取组织信息 + parameters: + - name: guild_id + in: path + required: true + schema: + type: string + format: uuid + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/OrgResp' + + /api/v1/guilds/{guild_id}/members: + post: + tags: [Social] + summary: 加入组织 + parameters: + - name: guild_id + in: path + required: true + schema: + type: string + format: uuid + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/OrgMemberResp' + + /api/v1/guilds/{guild_id}/members/me: + delete: + tags: [Social] + summary: 退出组织 + parameters: + - name: guild_id + in: path + required: true + schema: + type: string + format: uuid + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/OrgMemberResp' + + /api/v1/guilds/{guild_id}/members/{character_id}: + put: + tags: [Social] + summary: 管理成员权限 + parameters: + - name: guild_id + in: path + required: true + schema: + type: string + format: uuid + - name: character_id + in: path + required: true + schema: + type: string + format: uuid + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/UpdateRoleReq' + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/OrgMemberResp' + + /api/v1/relations/{relation_type}/requests: + post: + tags: [Social] + summary: 发起关系请求 + parameters: + - name: relation_type + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/RelationReq' + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/RelationResp' + + /api/v1/relations/{relation_type}/requests/{request_id}/respond: + post: + tags: [Social] + summary: 响应关系请求 + parameters: + - name: relation_type + in: path + required: true + schema: + type: string + - name: request_id + in: path + required: true + schema: + type: string + format: uuid + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/RelationResponseReq' + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/RelationResp' + + /api/v1/contracts: + post: + tags: [Social] + summary: 发布佣兵委托 + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/PublishContractReq' + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/ContractResp' + + /api/v1/contracts/{contract_id}/accept: + post: + tags: [Social] + summary: 接取佣兵委托 + parameters: + - name: contract_id + in: path + required: true + schema: + type: string + format: uuid + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/AcceptContractReq' + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/ContractResp' + + /api/v1/bounties: + post: + tags: [Social] + summary: 发布悬赏 + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/PublishBountyReq' + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/BountyResp' + + /api/v1/bounties/{bounty_id}/accept: + post: + tags: [Social] + summary: 接取悬赏 + parameters: + - name: bounty_id + in: path + required: true + schema: + type: string + format: uuid + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/BountyResp' + + /api/v1/world/regions/{region_id}: + get: + tags: [Map] + summary: 获取区域信息 + parameters: + - name: region_id + in: path + required: true + schema: + type: string + format: uuid + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/RegionResp' + + /api/v1/world/regions/{region_id}/nearby: + get: + tags: [Map] + summary: 查询附近玩家与事件 + parameters: + - name: region_id + in: path + required: true + schema: + type: string + format: uuid + - name: limit + in: query + schema: + type: integer + default: 30 + - name: event_types + in: query + schema: + type: array + items: + type: string + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/NearbyResp' + + /api/v1/instances/{instance_id}/enter: + post: + tags: [Map] + summary: 进入副本/遗迹 + parameters: + - name: instance_id + in: path + required: true + schema: + type: string + format: uuid + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/EnterInstanceReq' + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/InstanceRunResp' + + /api/v1/world/events: + get: + tags: [Map] + summary: 查询世界事件 + parameters: + - name: world_tier + in: query + schema: + type: integer + - name: region_id + in: query + schema: + type: string + format: uuid + - name: event_scope + in: query + schema: + type: string + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/WorldEventListResp' + post: + tags: [Map] + summary: 发起玩家事件 + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/PlayerEventReq' + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/WorldEventResp' + + /api/v1/disciples/{disciple_id}/dispatch: + post: + tags: [Disciple] + summary: 派遣弟子 + parameters: + - name: disciple_id + in: path + required: true + schema: + type: string + format: uuid + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/DispatchReq' + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/DiscipleMissionResp' + + /api/v1/missions/{mission_id}/claim: + post: + tags: [Disciple] + summary: 领取弟子/领地产出 + parameters: + - name: mission_id + in: path + required: true + schema: + type: string + format: uuid + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/MissionRewardResp' + + /api/v1/guilds/{guild_id}/territories/bids: + post: + tags: [Disciple] + summary: 帮派领地竞标 + parameters: + - name: guild_id + in: path + required: true + schema: + type: string + format: uuid + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/TerritoryBidReq' + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/TerritoryBidResp' + +components: + securitySchemes: + bearerAuth: + type: http + scheme: bearer + bearerFormat: JWT + description: "Nakama 颁发的 session token,格式 Authorization: Bearer " + + schemas: + CommonResp: + type: object + required: [code, message, trace_id] + properties: + code: + type: integer + description: 业务状态码,0 为成功 + message: + type: string + trace_id: + type: string + format: uuid + + RegisterReq: + type: object + required: [device_id, platform] + properties: + device_id: + type: string + platform: + type: string + enum: [ios, android, harmony, guest] + invite_code: + type: string + + LoginReq: + type: object + required: [device_id, platform] + properties: + device_id: + type: string + platform: + type: string + refresh_token: + type: string + + AuthResp: + allOf: + - $ref: '#/components/schemas/CommonResp' + - type: object + properties: + data: + type: object + properties: + player_id: + type: string + nakama_token: + type: string + expires_at: + type: string + format: date-time + is_new: + type: boolean + + CreateCharacterReq: + type: object + required: [name, race_id] + properties: + name: + type: string + race_id: + type: string + birth_world_tier: + type: integer + + CharacterResp: + allOf: + - $ref: '#/components/schemas/CommonResp' + - type: object + properties: + data: + type: object + properties: + character_id: + type: string + player_id: + type: string + name: + type: string + race_id: + type: string + world_tier: + type: integer + realm_tier: + type: integer + minor_realm: + type: integer + realm_status: + type: string + level: + type: integer + exp: + type: integer + format: int64 + status: + type: string + base_stats: + type: object + battle_stats: + type: object + san_current: + type: integer + san_max: + type: integer + crime_score: + type: integer + reputation_score: + type: integer + last_online_at: + type: string + format: date-time + created_at: + type: string + format: date-time + + RealmProgressResp: + allOf: + - $ref: '#/components/schemas/CommonResp' + - type: object + properties: + data: + type: object + properties: + realm_tier: + type: integer + minor_realm: + type: integer + realm_name: + type: string + exp: + type: integer + format: int64 + exp_to_next: + type: integer + format: int64 + max_unlocked_world_tier: + type: integer + realm_status: + type: string + breakthrough_ready: + type: boolean + tribulation_pending: + type: boolean + + BreakthroughReq: + type: object + required: [target_minor_realm, idempotency_key] + properties: + target_minor_realm: + type: integer + consumables: + type: array + items: + $ref: '#/components/schemas/MaterialCost' + helper_ids: + type: array + items: + type: string + format: uuid + idempotency_key: + type: string + + BreakthroughResp: + allOf: + - $ref: '#/components/schemas/CommonResp' + - type: object + properties: + data: + type: object + properties: + success: + type: boolean + from: + $ref: '#/components/schemas/RealmPoint' + to: + $ref: '#/components/schemas/RealmPoint' + exp_consumed: + type: integer + format: int64 + record_id: + type: string + special_event: + type: string + + TribulationReq: + type: object + required: [target_realm_tier] + properties: + target_realm_tier: + type: integer + tribulation_type: + type: string + consumables: + type: array + items: + $ref: '#/components/schemas/MaterialCost' + helper_ids: + type: array + items: + type: string + format: uuid + + TribulationResp: + allOf: + - $ref: '#/components/schemas/CommonResp' + - type: object + properties: + data: + type: object + properties: + tribulation_id: + type: string + status: + type: string + base_success_rate: + type: number + modified_success_rate: + type: number + estimated_ticks: + type: integer + start_at: + type: string + format: date-time + result: + type: string + from_realm_tier: + type: integer + to_realm_tier: + type: integer + penalties: + type: object + drops: + type: array + items: + $ref: '#/components/schemas/ItemAmount' + + WorldBreakReq: + type: object + required: [target_world_tier, confirm] + properties: + target_world_tier: + type: integer + key_item_instance_id: + type: string + format: uuid + confirm: + type: boolean + + WorldBreakResp: + allOf: + - $ref: '#/components/schemas/CommonResp' + - type: object + properties: + data: + type: object + properties: + success: + type: boolean + from_world_tier: + type: integer + to_world_tier: + type: integer + from_realm_tier: + type: integer + to_realm_tier: + type: integer + breakthrough_record_id: + type: string + world_event: + type: string + ruin_generated: + type: boolean + + StartCombatReq: + type: object + required: [battle_type, context_id] + properties: + battle_type: + type: string + context_id: + type: string + format: uuid + party_members: + type: array + items: + type: string + format: uuid + preferred_skills: + type: array + items: + type: string + format: uuid + + PvpChallengeReq: + type: object + required: [target_character_id] + properties: + target_character_id: + type: string + format: uuid + bounty_id: + type: string + format: uuid + use_paid_chance: + type: boolean + + CombatResp: + allOf: + - $ref: '#/components/schemas/CommonResp' + - type: object + properties: + data: + type: object + properties: + battle_id: + type: string + status: + type: string + result_summary: + type: object + drops: + type: object + death_penalty_applied: + type: boolean + honor_points: + type: integer + daily_pvp_count: + type: integer + daily_pvp_limit: + type: integer + + BattleReportResp: + allOf: + - $ref: '#/components/schemas/CommonResp' + - type: object + properties: + data: + type: object + properties: + battle_id: + type: string + type: + type: string + realm_tier: + type: integer + game_timestamp: + type: string + format: date-time + attacker: + type: object + defender: + type: object + rounds: + type: array + items: + type: object + result: + type: object + special_events: + type: array + items: + type: object + + ManualListResp: + allOf: + - $ref: '#/components/schemas/CommonResp' + - type: object + properties: + data: + type: object + properties: + total: + type: integer + list: + type: array + items: + $ref: '#/components/schemas/ManualItem' + + ManualItem: + type: object + properties: + manual_instance_id: + type: string + manual_id: + type: string + name: + type: string + current_layer: + type: integer + max_layer: + type: integer + proficiency: + type: integer + is_main: + type: boolean + is_buffing: + type: boolean + domain: + type: string + element: + type: string + source_tag: + type: string + + UpgradeManualReq: + type: object + required: [materials, idempotency_key] + properties: + materials: + type: array + items: + $ref: '#/components/schemas/MaterialCost' + use_insight_item: + type: boolean + idempotency_key: + type: string + + ManualResp: + allOf: + - $ref: '#/components/schemas/CommonResp' + - type: object + properties: + data: + type: object + properties: + manual_instance_id: + type: string + old_layer: + type: integer + new_layer: + type: integer + success: + type: boolean + proficiency_left: + type: integer + unlocked_skill: + $ref: '#/components/schemas/ItemAmount' + + BuffManualReq: + type: object + required: [slot_index] + properties: + slot_index: + type: integer + unset_others: + type: boolean + + BuffSlotResp: + allOf: + - $ref: '#/components/schemas/CommonResp' + - type: object + properties: + data: + type: object + properties: + slot_index: + type: integer + manual_instance_id: + type: string + buff_speed_bonus: + type: number + breakin_until: + type: string + format: date-time + + LearnSkillReq: + type: object + required: [source_type, source_id] + properties: + source_type: + type: string + source_id: + type: string + custom_name: + type: string + + SkillResp: + allOf: + - $ref: '#/components/schemas/CommonResp' + - type: object + properties: + data: + type: object + properties: + skill_instance_id: + type: string + skill_id: + type: string + name: + type: string + source_tag: + type: string + can_copy_to_jade_slip: + type: boolean + proficiency: + type: integer + instance_data: + type: object + + JadeSlipReq: + type: object + required: [consume_proficiency] + properties: + consume_proficiency: + type: boolean + copy_count: + type: integer + + ItemResp: + allOf: + - $ref: '#/components/schemas/CommonResp' + - type: object + properties: + data: + type: object + properties: + inventory_id: + type: string + item_id: + type: string + name: + type: string + quantity: + type: integer + instance_data: + type: object + proficiency_consumed: + type: integer + + CurrencyBalancesResp: + allOf: + - $ref: '#/components/schemas/CommonResp' + - type: object + properties: + data: + type: object + properties: + balances: + type: array + items: + $ref: '#/components/schemas/CurrencyBalance' + + CurrencyBalance: + type: object + properties: + currency_code: + type: string + amount: + type: string + total_earned: + type: string + total_spent: + type: string + + MarketOrderReq: + type: object + required: [inventory_id, currency_code, unit_price, quantity] + properties: + inventory_id: + type: string + format: uuid + currency_code: + type: string + unit_price: + type: string + quantity: + type: integer + duration_hours: + type: integer + + MarketOrderResp: + allOf: + - $ref: '#/components/schemas/CommonResp' + - type: object + properties: + data: + type: object + properties: + order_id: + type: string + status: + type: string + listed_at: + type: string + format: date-time + expired_at: + type: string + format: date-time + tax_rate: + type: number + + BuyOrderReq: + type: object + required: [quantity] + properties: + quantity: + type: integer + + TradeResp: + allOf: + - $ref: '#/components/schemas/CommonResp' + - type: object + properties: + data: + type: object + properties: + trade_id: + type: string + order_id: + type: string + quantity: + type: integer + total_price: + type: string + tax: + type: string + currency_code: + type: string + items: + type: array + items: + $ref: '#/components/schemas/ItemAmount' + + AuctionListResp: + allOf: + - $ref: '#/components/schemas/CommonResp' + - type: object + properties: + data: + type: object + properties: + total: + type: integer + list: + type: array + items: + $ref: '#/components/schemas/AuctionItem' + + AuctionItem: + type: object + properties: + auction_id: + type: string + seller_id: + type: string + item_id: + type: string + category: + type: string + currency_code: + type: string + start_price: + type: string + status: + type: string + started_at: + type: string + format: date-time + ended_at: + type: string + format: date-time + + BidReq: + type: object + required: [amount] + properties: + amount: + type: string + is_auto_bid: + type: boolean + auto_max_amount: + type: string + + BidResp: + allOf: + - $ref: '#/components/schemas/CommonResp' + - type: object + properties: + data: + type: object + properties: + bid_id: + type: string + auction_id: + type: string + amount: + type: string + deposit_paid: + type: string + is_auto_bid: + type: boolean + bid_at: + type: string + format: date-time + + IntelListResp: + allOf: + - $ref: '#/components/schemas/CommonResp' + - type: object + properties: + data: + type: object + properties: + total: + type: integer + list: + type: array + items: + $ref: '#/components/schemas/IntelItem' + + IntelItem: + type: object + properties: + order_id: + type: string + seller_id: + type: string + intel_type: + type: string + target_world_tier: + type: integer + content_summary: + type: string + currency_code: + type: string + price: + type: string + purchase_count: + type: integer + max_purchase: + type: integer + + IntelBuffResp: + allOf: + - $ref: '#/components/schemas/CommonResp' + - type: object + properties: + data: + type: object + properties: + buff_id: + type: string + order_id: + type: string + detail_data: + type: object + expires_at: + type: string + format: date-time + + CreateOrgReq: + type: object + required: [org_type, name] + properties: + org_type: + type: string + name: + type: string + region_id: + type: string + format: uuid + founding_members: + type: array + items: + type: string + format: uuid + + OrgResp: + allOf: + - $ref: '#/components/schemas/CommonResp' + - type: object + properties: + data: + type: object + properties: + guild_id: + type: string + name: + type: string + org_type: + type: string + leader_id: + type: string + level: + type: integer + member_limit: + type: integer + created_at: + type: string + format: date-time + + UpdateRoleReq: + type: object + required: [role, action] + properties: + role: + type: string + action: + type: string + + OrgMemberResp: + allOf: + - $ref: '#/components/schemas/CommonResp' + - type: object + properties: + data: + type: object + properties: + guild_id: + type: string + character_id: + type: string + role: + type: string + joined_at: + type: string + format: date-time + + RelationReq: + type: object + required: [target_character_id] + properties: + target_character_id: + type: string + format: uuid + vow_path: + type: string + + RelationResponseReq: + type: object + required: [action] + properties: + action: + type: string + + RelationResp: + allOf: + - $ref: '#/components/schemas/CommonResp' + - type: object + properties: + data: + type: object + properties: + request_id: + type: string + relation_type: + type: string + from_character_id: + type: string + to_character_id: + type: string + status: + type: string + + PublishContractReq: + type: object + required: [contract_type, difficulty, currency_code, base_reward] + properties: + contract_type: + type: string + difficulty: + type: integer + currency_code: + type: string + base_reward: + type: string + target_params: + type: object + valid_until: + type: string + format: date-time + + AcceptContractReq: + type: object + required: [accept_type] + properties: + accept_type: + type: string + disciple_id: + type: string + format: uuid + party_members: + type: array + items: + type: string + format: uuid + + ContractResp: + allOf: + - $ref: '#/components/schemas/CommonResp' + - type: object + properties: + data: + type: object + properties: + contract_id: + type: string + contract_type: + type: string + status: + type: string + publisher_id: + type: string + base_reward: + type: string + currency_code: + type: string + valid_until: + type: string + format: date-time + + PublishBountyReq: + type: object + required: [bounty_type, target_character_id, reward_amount, currency_code] + properties: + bounty_type: + type: string + target_character_id: + type: string + format: uuid + reward_amount: + type: string + currency_code: + type: string + valid_days: + type: integer + is_anonymous: + type: boolean + + BountyResp: + allOf: + - $ref: '#/components/schemas/CommonResp' + - type: object + properties: + data: + type: object + properties: + bounty_id: + type: string + bounty_type: + type: string + target_id: + type: string + reward_amount: + type: string + status: + type: string + valid_until: + type: string + format: date-time + + RegionResp: + allOf: + - $ref: '#/components/schemas/CommonResp' + - type: object + properties: + data: + type: object + properties: + region_id: + type: string + world_tier: + type: integer + name: + type: string + is_safe_zone: + type: boolean + pvp_rules: + type: object + weather: + type: string + resource_density: + type: integer + danger_level: + type: integer + nearby_player_count: + type: integer + + NearbyResp: + allOf: + - $ref: '#/components/schemas/CommonResp' + - type: object + properties: + data: + type: object + properties: + players: + type: array + items: + type: object + events: + type: array + items: + type: object + + EnterInstanceReq: + type: object + properties: + party_members: + type: array + items: + type: string + format: uuid + consumable_key_id: + type: string + format: uuid + use_stamina: + type: boolean + + InstanceRunResp: + allOf: + - $ref: '#/components/schemas/CommonResp' + - type: object + properties: + data: + type: object + properties: + run_id: + type: string + instance_id: + type: string + status: + type: string + difficulty_coefficient: + type: number + consumed_keys: + type: integer + started_at: + type: string + format: date-time + + WorldEventListResp: + allOf: + - $ref: '#/components/schemas/CommonResp' + - type: object + properties: + data: + type: object + properties: + total: + type: integer + list: + type: array + items: + $ref: '#/components/schemas/WorldEventItem' + + WorldEventItem: + type: object + properties: + event_id: + type: string + event_type: + type: string + world_tier: + type: integer + region_id: + type: string + title: + type: string + content: + type: string + expires_at: + type: string + format: date-time + + PlayerEventReq: + type: object + required: [event_type, region_id] + properties: + event_type: + type: string + region_id: + type: string + format: uuid + cost_items: + type: array + items: + $ref: '#/components/schemas/MaterialCost' + description: + type: string + + WorldEventResp: + allOf: + - $ref: '#/components/schemas/CommonResp' + - type: object + properties: + data: + type: object + properties: + event_id: + type: string + event_type: + type: string + status: + type: string + created_at: + type: string + format: date-time + + DispatchReq: + type: object + required: [target_type, target_id, duration_minutes] + properties: + target_type: + type: string + target_id: + type: string + format: uuid + duration_minutes: + type: integer + insurance_item_id: + type: string + format: uuid + + DiscipleMissionResp: + allOf: + - $ref: '#/components/schemas/CommonResp' + - type: object + properties: + data: + type: object + properties: + mission_id: + type: string + disciple_id: + type: string + target_type: + type: string + started_at: + type: string + format: date-time + ended_at: + type: string + format: date-time + status: + type: string + + MissionRewardResp: + allOf: + - $ref: '#/components/schemas/CommonResp' + - type: object + properties: + data: + type: object + properties: + mission_id: + type: string + result: + type: string + rewards: + type: object + + TerritoryBidReq: + type: object + required: [territory_id, bid_amount] + properties: + territory_id: + type: string + format: uuid + bid_amount: + type: string + is_renewal: + type: boolean + + TerritoryBidResp: + allOf: + - $ref: '#/components/schemas/CommonResp' + - type: object + properties: + data: + type: object + properties: + bid_id: + type: string + territory_id: + type: string + bid_amount: + type: string + deposit_locked: + type: string + window_end_at: + type: string + format: date-time + + MaterialCost: + type: object + required: [inventory_id, quantity] + properties: + inventory_id: + type: string + format: uuid + quantity: + type: integer + + RealmPoint: + type: object + properties: + realm_tier: + type: integer + minor_realm: + type: integer + + ItemAmount: + type: object + properties: + inventory_id: + type: string + item_id: + type: string + quantity: + type: integer diff --git a/api/proto/honghuang.proto b/api/proto/honghuang.proto new file mode 100644 index 0000000..ae365bc --- /dev/null +++ b/api/proto/honghuang.proto @@ -0,0 +1,867 @@ +syntax = "proto3"; + +package honghuang; + +option go_package = "github.com/honghuang-game/server/api/proto"; + +// ----------------------------------------------------------------------------- +// 通用结构 +// ----------------------------------------------------------------------------- + +message CommonError { + int32 code = 1; + string message = 2; +} + +message Pagination { + int32 page = 1; + int32 page_size = 2; + int32 total = 3; +} + +message ItemAmount { + string inventory_id = 1; + string item_id = 2; + int32 quantity = 3; +} + +message CurrencyAmount { + string currency_code = 1; + string amount = 2; // 使用字符串保留 numeric 精度 +} + +message MaterialCost { + string inventory_id = 1; + int32 quantity = 2; +} + +message RealmPoint { + int32 realm_tier = 1; + int32 minor_realm = 2; +} + +// ----------------------------------------------------------------------------- +// 账号/角色 +// ----------------------------------------------------------------------------- + +message RegisterReq { + string device_id = 1; + string platform = 2; + string invite_code = 3; +} + +message LoginReq { + string device_id = 1; + string platform = 2; + string refresh_token = 3; +} + +message AuthResp { + int32 code = 1; + string message = 2; + string trace_id = 3; + string player_id = 4; + string nakama_token = 5; + string expires_at = 6; + bool is_new = 7; +} + +message CreateCharacterReq { + string name = 1; + string race_id = 2; + int32 birth_world_tier = 3; +} + +message GetCharacterReq { + string character_id = 1; + bool with_snapshot = 2; +} + +message CharacterResp { + int32 code = 1; + string message = 2; + string trace_id = 3; + string character_id = 4; + string player_id = 5; + string name = 6; + string race_id = 7; + int32 world_tier = 8; + int32 realm_tier = 9; + int32 minor_realm = 10; + string realm_status = 11; + int32 level = 12; + int64 exp = 13; + string status = 14; + string base_stats = 15; // JSON + string battle_stats = 16; // JSON + int32 san_current = 17; + int32 san_max = 18; + int32 crime_score = 19; + int32 heavenly_value = 20; + int32 karma_value = 21; + int32 reputation_score = 22; + string last_online_at = 23; + string created_at = 24; +} + +// ----------------------------------------------------------------------------- +// 修炼/境界 +// ----------------------------------------------------------------------------- + +message RealmReq { + string character_id = 1; +} + +message RealmProgressResp { + int32 code = 1; + string message = 2; + string trace_id = 3; + int32 realm_tier = 4; + int32 minor_realm = 5; + string realm_name = 6; + int64 exp = 7; + int64 exp_to_next = 8; + int32 max_unlocked_world_tier = 9; + string realm_status = 10; + bool breakthrough_ready = 11; + bool tribulation_pending = 12; +} + +message BreakthroughReq { + string character_id = 1; + int32 target_minor_realm = 2; + repeated MaterialCost consumables = 3; + repeated string helper_ids = 4; + string idempotency_key = 5; +} + +message BreakthroughResp { + int32 code = 1; + string message = 2; + string trace_id = 3; + bool success = 4; + RealmPoint from = 5; + RealmPoint to = 6; + int64 exp_consumed = 7; + string record_id = 8; + string special_event = 9; +} + +message TribulationReq { + string character_id = 1; + int32 target_realm_tier = 2; + string tribulation_type = 3; + repeated MaterialCost consumables = 4; + repeated string helper_ids = 5; +} + +message TribulationResp { + int32 code = 1; + string message = 2; + string trace_id = 3; + string tribulation_id = 4; + string status = 5; + double base_success_rate = 6; + double modified_success_rate = 7; + int32 estimated_ticks = 8; + string start_at = 9; + string result = 10; + int32 from_realm_tier = 11; + int32 to_realm_tier = 12; + string penalties = 13; // JSON + repeated ItemAmount drops = 14; +} + +message WorldBreakReq { + string character_id = 1; + int32 target_world_tier = 2; + string key_item_instance_id = 3; + bool confirm = 4; +} + +message WorldBreakResp { + int32 code = 1; + string message = 2; + string trace_id = 3; + bool success = 4; + int32 from_world_tier = 5; + int32 to_world_tier = 6; + int32 from_realm_tier = 7; + int32 to_realm_tier = 8; + string breakthrough_record_id = 9; + string world_event = 10; + bool ruin_generated = 11; +} + +// ----------------------------------------------------------------------------- +// 战斗 +// ----------------------------------------------------------------------------- + +message StartCombatReq { + string battle_type = 1; + string context_id = 2; + repeated string party_members = 3; + repeated string preferred_skills = 4; +} + +message PvpChallengeReq { + string target_character_id = 1; + string bounty_id = 2; + bool use_paid_chance = 3; +} + +message CombatResp { + int32 code = 1; + string message = 2; + string trace_id = 3; + string battle_id = 4; + string status = 5; + string result_summary = 6; // JSON + string drops = 7; // JSON + bool death_penalty_applied = 8; + int32 honor_points = 9; + int32 daily_pvp_count = 10; + int32 daily_pvp_limit = 11; +} + +message BattleReportReq { + string battle_id = 1; +} + +message BattleReportResp { + int32 code = 1; + string message = 2; + string trace_id = 3; + string battle_id = 4; + string type = 5; + int32 realm_tier = 6; + string game_timestamp = 7; + string attacker = 8; // JSON + string defender = 9; // JSON + string rounds = 10; // JSON + string result = 11; // JSON + string special_events = 12; // JSON +} + +// ----------------------------------------------------------------------------- +// 功法 +// ----------------------------------------------------------------------------- + +message ManualListReq { + string character_id = 1; + bool is_buffing = 2; + int32 page = 3; + int32 page_size = 4; +} + +message ManualItem { + string manual_instance_id = 1; + string manual_id = 2; + string name = 3; + int32 current_layer = 4; + int32 max_layer = 5; + int32 proficiency = 6; + bool is_main = 7; + bool is_buffing = 8; + string domain = 9; + string element = 10; + string source_tag = 11; +} + +message ManualListResp { + int32 code = 1; + string message = 2; + string trace_id = 3; + int32 total = 4; + repeated ManualItem list = 5; +} + +message UpgradeManualReq { + string character_id = 1; + string manual_instance_id = 2; + repeated MaterialCost materials = 3; + bool use_insight_item = 4; + string idempotency_key = 5; +} + +message ManualResp { + int32 code = 1; + string message = 2; + string trace_id = 3; + string manual_instance_id = 4; + int32 old_layer = 5; + int32 new_layer = 6; + bool success = 7; + int32 proficiency_left = 8; + ItemAmount unlocked_skill = 9; +} + +message BuffManualReq { + string character_id = 1; + string manual_instance_id = 2; + int32 slot_index = 3; + bool unset_others = 4; +} + +message BuffSlotResp { + int32 code = 1; + string message = 2; + string trace_id = 3; + int32 slot_index = 4; + string manual_instance_id = 5; + double buff_speed_bonus = 6; + string breakin_until = 7; +} + +// ----------------------------------------------------------------------------- +// 技能 +// ----------------------------------------------------------------------------- + +message LearnSkillReq { + string character_id = 1; + string source_type = 2; + string source_id = 3; + string custom_name = 4; +} + +message SkillResp { + int32 code = 1; + string message = 2; + string trace_id = 3; + string skill_instance_id = 4; + string skill_id = 5; + string name = 6; + string source_tag = 7; + bool can_copy_to_jade_slip = 8; + int32 proficiency = 9; + string instance_data = 10; // JSON +} + +message JadeSlipReq { + string character_id = 1; + string skill_instance_id = 2; + bool consume_proficiency = 3; + int32 copy_count = 4; +} + +message ItemResp { + int32 code = 1; + string message = 2; + string trace_id = 3; + string inventory_id = 4; + string item_id = 5; + string name = 6; + int32 quantity = 7; + string instance_data = 8; // JSON + int32 proficiency_consumed = 9; +} + +// ----------------------------------------------------------------------------- +// 经济/背包 +// ----------------------------------------------------------------------------- + +message CurrencyReq { + string character_id = 1; +} + +message CurrencyBalance { + string currency_code = 1; + string amount = 2; + string total_earned = 3; + string total_spent = 4; +} + +message CurrencyBalancesResp { + int32 code = 1; + string message = 2; + string trace_id = 3; + repeated CurrencyBalance balances = 4; +} + +message MarketOrderReq { + string inventory_id = 1; + string currency_code = 2; + string unit_price = 3; + int32 quantity = 4; + int32 duration_hours = 5; +} + +message MarketOrderResp { + int32 code = 1; + string message = 2; + string trace_id = 3; + string order_id = 4; + string status = 5; + string listed_at = 6; + string expired_at = 7; + double tax_rate = 8; +} + +message OrderIdReq { + string order_id = 1; +} + +message BuyOrderReq { + string order_id = 1; + int32 quantity = 2; +} + +message TradeResp { + int32 code = 1; + string message = 2; + string trace_id = 3; + string trade_id = 4; + string order_id = 5; + int32 quantity = 6; + string total_price = 7; + string tax = 8; + string currency_code = 9; + repeated ItemAmount items = 10; +} + +message AuctionListReq { + int32 world_tier = 1; + string auction_type = 2; + string category = 3; + string status = 4; + int32 page = 5; + int32 page_size = 6; +} + +message AuctionItem { + string auction_id = 1; + string seller_id = 2; + string item_id = 3; + string category = 4; + string currency_code = 5; + string start_price = 6; + string status = 7; + string started_at = 8; + string ended_at = 9; +} + +message AuctionListResp { + int32 code = 1; + string message = 2; + string trace_id = 3; + int32 total = 4; + repeated AuctionItem list = 5; +} + +message BidReq { + string auction_id = 1; + string amount = 2; + bool is_auto_bid = 3; + string auto_max_amount = 4; +} + +message BidResp { + int32 code = 1; + string message = 2; + string trace_id = 3; + string bid_id = 4; + string auction_id = 5; + string amount = 6; + string deposit_paid = 7; + bool is_auto_bid = 8; + string bid_at = 9; +} + +message IntelListReq { + string intel_type = 1; + int32 target_world_tier = 2; + int32 page = 3; + int32 page_size = 4; +} + +message IntelItem { + string order_id = 1; + string seller_id = 2; + string intel_type = 3; + int32 target_world_tier = 4; + string content_summary = 5; + string currency_code = 6; + string price = 7; + int32 purchase_count = 8; + int32 max_purchase = 9; +} + +message IntelListResp { + int32 code = 1; + string message = 2; + string trace_id = 3; + int32 total = 4; + repeated IntelItem list = 5; +} + +message BuyIntelReq { + string order_id = 1; +} + +message IntelBuffResp { + int32 code = 1; + string message = 2; + string trace_id = 3; + string buff_id = 4; + string order_id = 5; + string detail_data = 6; // JSON + string expires_at = 7; +} + +// ----------------------------------------------------------------------------- +// 社交/组织/悬赏 +// ----------------------------------------------------------------------------- + +message CreateOrgReq { + string org_type = 1; + string name = 2; + string region_id = 3; + repeated string founding_members = 4; +} + +message OrgIdReq { + string guild_id = 1; +} + +message OrgResp { + int32 code = 1; + string message = 2; + string trace_id = 3; + string guild_id = 4; + string name = 5; + string org_type = 6; + string leader_id = 7; + int32 level = 8; + int32 member_limit = 9; + string created_at = 10; +} + +message OrgMemberReq { + string guild_id = 1; +} + +message OrgMemberResp { + int32 code = 1; + string message = 2; + string trace_id = 3; + string guild_id = 4; + string character_id = 5; + string role = 6; + string joined_at = 7; +} + +message UpdateRoleReq { + string guild_id = 1; + string character_id = 2; + string role = 3; + string action = 4; +} + +message RelationReq { + string relation_type = 1; + string target_character_id = 2; + string vow_path = 3; +} + +message RelationResponseReq { + string relation_type = 1; + string request_id = 2; + string action = 3; +} + +message RelationResp { + int32 code = 1; + string message = 2; + string trace_id = 3; + string request_id = 4; + string relation_type = 5; + string from_character_id = 6; + string to_character_id = 7; + string status = 8; +} + +message PublishContractReq { + string contract_type = 1; + int32 difficulty = 2; + string currency_code = 3; + string base_reward = 4; + string target_params = 5; // JSON + string valid_until = 6; +} + +message AcceptContractReq { + string contract_id = 1; + string accept_type = 2; + string disciple_id = 3; + repeated string party_members = 4; +} + +message ContractResp { + int32 code = 1; + string message = 2; + string trace_id = 3; + string contract_id = 4; + string contract_type = 5; + string status = 6; + string publisher_id = 7; + string base_reward = 8; + string currency_code = 9; + string valid_until = 10; +} + +message PublishBountyReq { + string bounty_type = 1; + string target_character_id = 2; + string reward_amount = 3; + string currency_code = 4; + int32 valid_days = 5; + bool is_anonymous = 6; +} + +message BountyIdReq { + string bounty_id = 1; +} + +message BountyResp { + int32 code = 1; + string message = 2; + string trace_id = 3; + string bounty_id = 4; + string bounty_type = 5; + string target_id = 6; + string reward_amount = 7; + string status = 8; + string valid_until = 9; +} + +// ----------------------------------------------------------------------------- +// 地图/副本/事件 +// ----------------------------------------------------------------------------- + +message RegionReq { + string region_id = 1; +} + +message RegionResp { + int32 code = 1; + string message = 2; + string trace_id = 3; + string region_id = 4; + int32 world_tier = 5; + string name = 6; + bool is_safe_zone = 7; + string pvp_rules = 8; // JSON + string weather = 9; + int32 resource_density = 10; + int32 danger_level = 11; + int32 nearby_player_count = 12; +} + +message NearbyReq { + string region_id = 1; + int32 limit = 2; + repeated string event_types = 3; +} + +message NearbyResp { + int32 code = 1; + string message = 2; + string trace_id = 3; + string players = 4; // JSON + string events = 5; // JSON +} + +message EnterInstanceReq { + string instance_id = 1; + repeated string party_members = 2; + string consumable_key_id = 3; + bool use_stamina = 4; +} + +message InstanceRunResp { + int32 code = 1; + string message = 2; + string trace_id = 3; + string run_id = 4; + string instance_id = 5; + string status = 6; + double difficulty_coefficient = 7; + int32 consumed_keys = 8; + string started_at = 9; +} + +message WorldEventReq { + int32 world_tier = 1; + string region_id = 2; + string event_scope = 3; + int32 page = 4; + int32 page_size = 5; +} + +message WorldEventItem { + string event_id = 1; + string event_type = 2; + int32 world_tier = 3; + string region_id = 4; + string title = 5; + string content = 6; + string expires_at = 7; +} + +message WorldEventListResp { + int32 code = 1; + string message = 2; + string trace_id = 3; + int32 total = 4; + repeated WorldEventItem list = 5; +} + +message PlayerEventReq { + string event_type = 1; + string region_id = 2; + repeated MaterialCost cost_items = 3; + string description = 4; +} + +message WorldEventResp { + int32 code = 1; + string message = 2; + string trace_id = 3; + string event_id = 4; + string event_type = 5; + string status = 6; + string created_at = 7; +} + +// ----------------------------------------------------------------------------- +// 弟子/领地 +// ----------------------------------------------------------------------------- + +message DispatchReq { + string disciple_id = 1; + string target_type = 2; + string target_id = 3; + int32 duration_minutes = 4; + string insurance_item_id = 5; +} + +message DiscipleMissionResp { + int32 code = 1; + string message = 2; + string trace_id = 3; + string mission_id = 4; + string disciple_id = 5; + string target_type = 6; + string started_at = 7; + string ended_at = 8; + string status = 9; +} + +message MissionIdReq { + string mission_id = 1; +} + +message MissionRewardResp { + int32 code = 1; + string message = 2; + string trace_id = 3; + string mission_id = 4; + string result = 5; + string rewards = 6; // JSON +} + +message TerritoryBidReq { + string guild_id = 1; + string territory_id = 2; + string bid_amount = 3; + bool is_renewal = 4; +} + +message TerritoryBidResp { + int32 code = 1; + string message = 2; + string trace_id = 3; + string bid_id = 4; + string territory_id = 5; + string bid_amount = 6; + string deposit_locked = 7; + string window_end_at = 8; +} + +// ----------------------------------------------------------------------------- +// 服务定义 +// ----------------------------------------------------------------------------- + +service AuthService { + rpc Register (RegisterReq) returns (AuthResp); + rpc Login (LoginReq) returns (AuthResp); +} + +service CharacterService { + rpc CreateCharacter (CreateCharacterReq) returns (CharacterResp); + rpc GetCharacter (GetCharacterReq) returns (CharacterResp); +} + +service RealmService { + rpc GetRealmProgress (RealmReq) returns (RealmProgressResp); + rpc AttemptBreakthrough (BreakthroughReq) returns (BreakthroughResp); + rpc StartTribulation (TribulationReq) returns (TribulationResp); + rpc GetTribulationResult (TribulationReq) returns (TribulationResp); + rpc WorldBreak (WorldBreakReq) returns (WorldBreakResp); +} + +service BattleService { + rpc StartCombat (StartCombatReq) returns (CombatResp); + rpc GetBattleReport (BattleReportReq) returns (BattleReportResp); + rpc PvpChallenge (PvpChallengeReq) returns (CombatResp); +} + +service ManualService { + rpc ListManuals (ManualListReq) returns (ManualListResp); + rpc UpgradeManual (UpgradeManualReq) returns (ManualResp); + rpc SetBuffingManual (BuffManualReq) returns (BuffSlotResp); +} + +service SkillService { + rpc LearnSkill (LearnSkillReq) returns (SkillResp); + rpc CreateJadeSlip (JadeSlipReq) returns (ItemResp); +} + +service EconomyService { + rpc GetCurrencyBalances (CurrencyReq) returns (CurrencyBalancesResp); + rpc CreateMarketOrder (MarketOrderReq) returns (MarketOrderResp); + rpc CancelMarketOrder (OrderIdReq) returns (MarketOrderResp); + rpc BuyMarketOrder (BuyOrderReq) returns (TradeResp); + rpc ListAuctions (AuctionListReq) returns (AuctionListResp); + rpc BidAuction (BidReq) returns (BidResp); + rpc ListIntelligence (IntelListReq) returns (IntelListResp); + rpc BuyIntelligence (BuyIntelReq) returns (IntelBuffResp); +} + +service SocialService { + rpc CreateOrganization (CreateOrgReq) returns (OrgResp); + rpc GetOrganization (OrgIdReq) returns (OrgResp); + rpc JoinOrganization (OrgMemberReq) returns (OrgMemberResp); + rpc LeaveOrganization (OrgIdReq) returns (OrgMemberResp); + rpc UpdateMemberRole (UpdateRoleReq) returns (OrgMemberResp); + rpc SendRelationRequest (RelationReq) returns (RelationResp); + rpc RespondRelationRequest (RelationResponseReq) returns (RelationResp); + rpc PublishContract (PublishContractReq) returns (ContractResp); + rpc AcceptContract (AcceptContractReq) returns (ContractResp); + rpc PublishBounty (PublishBountyReq) returns (BountyResp); + rpc AcceptBounty (BountyIdReq) returns (BountyResp); +} + +service MapService { + rpc GetRegion (RegionReq) returns (RegionResp); + rpc GetNearby (NearbyReq) returns (NearbyResp); + rpc EnterInstance (EnterInstanceReq) returns (InstanceRunResp); + rpc ListWorldEvents (WorldEventReq) returns (WorldEventListResp); + rpc PublishPlayerEvent (PlayerEventReq) returns (WorldEventResp); +} + +service DiscipleService { + rpc DispatchDisciple (DispatchReq) returns (DiscipleMissionResp); + rpc ClaimMissionOutput (MissionIdReq) returns (MissionRewardResp); + rpc BidTerritory (TerritoryBidReq) returns (TerritoryBidResp); +} diff --git a/database/migrations/001_init_schema.down.sql b/database/migrations/001_init_schema.down.sql new file mode 100644 index 0000000..9b57190 --- /dev/null +++ b/database/migrations/001_init_schema.down.sql @@ -0,0 +1,57 @@ +-- 按依赖顺序删除所有表(使用 CASCADE 处理循环/复杂外键) + +DROP TABLE IF EXISTS daily_reset_tracking CASCADE; +DROP TABLE IF EXISTS nacos_configs CASCADE; +DROP TABLE IF EXISTS reputation_records CASCADE; +DROP TABLE IF EXISTS sworn_brothers CASCADE; +DROP TABLE IF EXISTS lovers CASCADE; +DROP TABLE IF EXISTS social_relations CASCADE; +DROP TABLE IF EXISTS tribulation_records CASCADE; +DROP TABLE IF EXISTS world_ruin_records CASCADE; +DROP TABLE IF EXISTS instance_loot CASCADE; +DROP TABLE IF EXISTS instance_runs CASCADE; +DROP TABLE IF EXISTS instances CASCADE; +DROP TABLE IF EXISTS player_kills CASCADE; +DROP TABLE IF EXISTS battle_logs CASCADE; +DROP TABLE IF EXISTS battles CASCADE; +DROP TABLE IF EXISTS zone_explorations CASCADE; +DROP TABLE IF EXISTS zones CASCADE; +DROP TABLE IF EXISTS regions CASCADE; +DROP TABLE IF EXISTS maps CASCADE; +DROP TABLE IF EXISTS world_layers CASCADE; +DROP TABLE IF EXISTS manhunt_records CASCADE; +DROP TABLE IF EXISTS contract_participants CASCADE; +DROP TABLE IF EXISTS bounties CASCADE; +DROP TABLE IF EXISTS contracts CASCADE; +DROP TABLE IF EXISTS disciple_missions CASCADE; +DROP TABLE IF EXISTS disciples CASCADE; +DROP TABLE IF EXISTS intelligence_orders CASCADE; +DROP TABLE IF EXISTS auction_blacklist_records CASCADE; +DROP TABLE IF EXISTS auction_bids CASCADE; +DROP TABLE IF EXISTS auctions CASCADE; +DROP TABLE IF EXISTS market_orders CASCADE; +DROP TABLE IF EXISTS guild_warehouses CASCADE; +DROP TABLE IF EXISTS guild_diplomacy CASCADE; +DROP TABLE IF EXISTS guild_territories CASCADE; +DROP TABLE IF EXISTS guild_members CASCADE; +DROP TABLE IF EXISTS guilds CASCADE; +DROP TABLE IF EXISTS economy_audit_logs CASCADE; +DROP TABLE IF EXISTS currency_balances CASCADE; +DROP TABLE IF EXISTS currencies CASCADE; +DROP TABLE IF EXISTS equipments CASCADE; +DROP TABLE IF EXISTS inventories CASCADE; +DROP TABLE IF EXISTS items CASCADE; +DROP TABLE IF EXISTS character_skills CASCADE; +DROP TABLE IF EXISTS skills CASCADE; +DROP TABLE IF EXISTS character_manuals CASCADE; +DROP TABLE IF EXISTS manuals CASCADE; +DROP TABLE IF EXISTS realm_breakthrough_records CASCADE; +DROP TABLE IF EXISTS character_realms CASCADE; +DROP TABLE IF EXISTS realms CASCADE; +DROP TABLE IF EXISTS race_currency_wallets CASCADE; +DROP TABLE IF EXISTS character_race_states CASCADE; +DROP TABLE IF EXISTS characters CASCADE; +DROP TABLE IF EXISTS players CASCADE; +DROP TABLE IF EXISTS race_templates CASCADE; + +DROP EXTENSION IF EXISTS pgcrypto; diff --git a/database/migrations/001_init_schema.up.sql b/database/migrations/001_init_schema.up.sql new file mode 100644 index 0000000..efeb005 --- /dev/null +++ b/database/migrations/001_init_schema.up.sql @@ -0,0 +1,970 @@ +-- TDD-04 数据库表结构初始化 +-- 适用 PostgreSQL 16 + pg_partman(分区扩展可选) +-- 命名约定:小写下划线,主键 uuid,金额 numeric(20,4),JSONB 存半结构化数据 + +CREATE EXTENSION IF NOT EXISTS pgcrypto; + +-------------------------------------------------------------------------------- +-- 0. 开发参考表(种族、境界、货币静态配置) +-------------------------------------------------------------------------------- + +CREATE TABLE IF NOT EXISTS race_templates ( + id VARCHAR(32) PRIMARY KEY, + name VARCHAR(64) NOT NULL, + category VARCHAR(16) NOT NULL DEFAULT 'common', -- common / rare + can_create BOOLEAN NOT NULL DEFAULT true, + description TEXT, + created_at TIMESTAMPTZ DEFAULT NOW() +); + +-------------------------------------------------------------------------------- +-- 1. 账号与角色 +-------------------------------------------------------------------------------- + +CREATE TABLE IF NOT EXISTS players ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + nakama_user_id UUID UNIQUE, + platform VARCHAR(32), + device_id_hash VARCHAR(128) UNIQUE, + status VARCHAR(16) NOT NULL DEFAULT 'active', -- active / banned / deleted + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE TABLE IF NOT EXISTS characters ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + player_id UUID NOT NULL REFERENCES players(id) ON DELETE CASCADE, + name VARCHAR(64) UNIQUE NOT NULL, + race_id VARCHAR(32) NOT NULL, + birth_race_id VARCHAR(32) NOT NULL, + birth_world_tier SMALLINT NOT NULL DEFAULT 1, + world_tier SMALLINT NOT NULL DEFAULT 1, + realm_tier SMALLINT NOT NULL DEFAULT 1, + minor_realm SMALLINT NOT NULL DEFAULT 1, + realm_status VARCHAR(16) NOT NULL DEFAULT 'normal', -- normal / tribulation_pending / breakthrough_ready + level INT NOT NULL DEFAULT 1, + exp BIGINT NOT NULL DEFAULT 0, + power BIGINT NOT NULL DEFAULT 0, + status VARCHAR(16) NOT NULL DEFAULT 'active', -- active / dead / sealed / deleted + base_stats JSONB NOT NULL DEFAULT '{}', + battle_stats JSONB NOT NULL DEFAULT '{}', + san_current SMALLINT NOT NULL DEFAULT 100, + san_max SMALLINT NOT NULL DEFAULT 100, + crime_score INT NOT NULL DEFAULT 0, + heavenly_value INT NOT NULL DEFAULT 0, + karma_value INT NOT NULL DEFAULT 0, + reputation_score INT NOT NULL DEFAULT 0, + mercenary_score INT NOT NULL DEFAULT 0, + hunter_prestige INT NOT NULL DEFAULT 0, + last_online_at TIMESTAMPTZ, + daily_reset_at TIMESTAMPTZ, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE INDEX idx_characters_player ON characters(player_id); +CREATE INDEX idx_characters_realm_rank ON characters(world_tier, realm_tier, power DESC); +CREATE INDEX idx_characters_realm_minor ON characters(realm_tier, minor_realm, power DESC); +CREATE INDEX idx_characters_last_online ON characters(last_online_at); +CREATE INDEX idx_characters_status ON characters(status); + +CREATE TABLE IF NOT EXISTS character_race_states ( + character_id UUID PRIMARY KEY REFERENCES characters(id) ON DELETE CASCADE, + main_race_id VARCHAR(32) NOT NULL, + sub_branch_id VARCHAR(32), + bloodline_data JSONB NOT NULL DEFAULT '{}', + is_rare_race BOOLEAN NOT NULL DEFAULT false, + rebirth_count SMALLINT NOT NULL DEFAULT 0, + conversion_cooldown_until TIMESTAMPTZ, + race_talents JSONB NOT NULL DEFAULT '{}', + hidden_talents JSONB NOT NULL DEFAULT '{}', + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE TABLE IF NOT EXISTS race_currency_wallets ( + character_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + race_currency_code VARCHAR(32) NOT NULL, + amount NUMERIC(20,4) NOT NULL DEFAULT 0, + total_earned NUMERIC(20,4) NOT NULL DEFAULT 0, + updated_at TIMESTAMPTZ DEFAULT NOW(), + PRIMARY KEY (character_id, race_currency_code) +); + +-------------------------------------------------------------------------------- +-- 2. 境界 +-------------------------------------------------------------------------------- + +CREATE TABLE IF NOT EXISTS realms ( + tier SMALLINT PRIMARY KEY, + minor_realm_max SMALLINT NOT NULL DEFAULT 3, + name VARCHAR(64) NOT NULL, + world_tier SMALLINT NOT NULL, + main_currency_code VARCHAR(32) NOT NULL, + is_tribulation_required BOOLEAN NOT NULL DEFAULT true, + base_success_rate NUMERIC(5,4) NOT NULL DEFAULT 0.5, + attr_growth_template JSONB NOT NULL DEFAULT '{}' +); + +CREATE TABLE IF NOT EXISTS character_realms ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + character_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + realm_tier SMALLINT NOT NULL, + max_minor_reached SMALLINT NOT NULL DEFAULT 1, + exp_in_tier BIGINT NOT NULL DEFAULT 0, + stats_snapshot JSONB NOT NULL DEFAULT '{}', + is_current BOOLEAN NOT NULL DEFAULT false, + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE INDEX idx_character_realms_character ON character_realms(character_id); +CREATE INDEX idx_character_realms_current ON character_realms(character_id, is_current); + +CREATE TABLE IF NOT EXISTS realm_breakthrough_records ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + character_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + from_realm_tier SMALLINT NOT NULL, + to_realm_tier SMALLINT NOT NULL, + from_minor_realm SMALLINT NOT NULL, + to_minor_realm SMALLINT NOT NULL, + is_success BOOLEAN NOT NULL, + is_break_world_barrier BOOLEAN NOT NULL DEFAULT false, + source_world_tier SMALLINT NOT NULL, + target_world_tier SMALLINT NOT NULL, + created_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE INDEX idx_realm_breakthrough_character ON realm_breakthrough_records(character_id); +CREATE INDEX idx_realm_breakthrough_created ON realm_breakthrough_records(created_at); + +-------------------------------------------------------------------------------- +-- 3. 功法与技能 +-------------------------------------------------------------------------------- + +CREATE TABLE IF NOT EXISTS manuals ( + id VARCHAR(64) PRIMARY KEY, + name VARCHAR(128) NOT NULL, + category VARCHAR(32) NOT NULL, -- universal / profession / racial / unique + domain VARCHAR(32) NOT NULL, + element VARCHAR(16) NOT NULL DEFAULT 'none', + alignment VARCHAR(16) NOT NULL DEFAULT 'neutral', + max_layers SMALLINT NOT NULL DEFAULT 1, + required_race VARCHAR(32)[], + required_profession VARCHAR(32)[], + base_attr JSONB NOT NULL DEFAULT '{}', + skill_unlock_layers JSONB NOT NULL DEFAULT '[]', + version INT NOT NULL DEFAULT 1 +); + +CREATE TABLE IF NOT EXISTS character_manuals ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + character_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + manual_id VARCHAR(64) NOT NULL REFERENCES manuals(id), + instance_data JSONB NOT NULL DEFAULT '{}', + is_buffing BOOLEAN NOT NULL DEFAULT false, + buff_data JSONB NOT NULL DEFAULT '{}', + source_tag VARCHAR(32) NOT NULL DEFAULT 'ORIGINAL', + can_copy_to_jade_slip BOOLEAN NOT NULL DEFAULT false, + copy_count_left SMALLINT NOT NULL DEFAULT 0, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE INDEX idx_character_manuals_character ON character_manuals(character_id); +CREATE INDEX idx_character_manuals_buffing ON character_manuals(character_id, is_buffing); +CREATE INDEX idx_character_manuals_manual ON character_manuals(manual_id); +CREATE INDEX idx_character_manuals_instance_gin ON character_manuals USING GIN (instance_data jsonb_path_ops); + +CREATE TABLE IF NOT EXISTS skills ( + id VARCHAR(64) PRIMARY KEY, + name VARCHAR(128) NOT NULL, + category VARCHAR(32) NOT NULL, + domain VARCHAR(32) NOT NULL, + archetype VARCHAR(32) NOT NULL, + element VARCHAR(16) NOT NULL DEFAULT 'none', + alignment VARCHAR(16) NOT NULL DEFAULT 'neutral', + damage_type VARCHAR(16) NOT NULL DEFAULT 'physical', + scaling_attr VARCHAR(8), + is_eldritch BOOLEAN NOT NULL DEFAULT false, + san_cost SMALLINT NOT NULL DEFAULT 0, + san_gate JSONB NOT NULL DEFAULT '{}', + san_scaling NUMERIC(6,4) NOT NULL DEFAULT 0, + requirements JSONB NOT NULL DEFAULT '{}', + continuous_cost JSONB NOT NULL DEFAULT '{}', + flow VARCHAR(32) NOT NULL DEFAULT 'transcript_jade_ok', + base_template JSONB NOT NULL DEFAULT '{}', + version INT NOT NULL DEFAULT 1 +); + +CREATE TABLE IF NOT EXISTS character_skills ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + character_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + skill_id VARCHAR(64) NOT NULL REFERENCES skills(id), + custom_name VARCHAR(128), + instance_data JSONB NOT NULL DEFAULT '{}', + source_tag VARCHAR(32) NOT NULL DEFAULT 'ORIGINAL', + proficiency INT NOT NULL DEFAULT 0, + is_unique BOOLEAN NOT NULL DEFAULT false, + unique_holder_until TIMESTAMPTZ, + lineage JSONB NOT NULL DEFAULT '{}', + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE INDEX idx_character_skills_character ON character_skills(character_id); +CREATE INDEX idx_character_skills_unique ON character_skills(character_id, is_unique); +CREATE INDEX idx_character_skills_skill ON character_skills(skill_id); +CREATE INDEX idx_character_skills_instance_gin ON character_skills USING GIN (instance_data jsonb_path_ops); + +-------------------------------------------------------------------------------- +-- 4. 物品、装备与经济 +-------------------------------------------------------------------------------- + +CREATE TABLE IF NOT EXISTS items ( + id VARCHAR(64) PRIMARY KEY, + name VARCHAR(128) NOT NULL, + category VARCHAR(32) NOT NULL, + sub_category VARCHAR(32), + stackable BOOLEAN NOT NULL DEFAULT false, + max_stack INT NOT NULL DEFAULT 1, + bind_type VARCHAR(16) NOT NULL DEFAULT 'none', + world_tier SMALLINT NOT NULL DEFAULT 1, + base_attr_template JSONB NOT NULL DEFAULT '{}', + random_affix_pool JSONB NOT NULL DEFAULT '{}', + script_id VARCHAR(64), + version INT NOT NULL DEFAULT 1 +); + +CREATE TABLE IF NOT EXISTS inventories ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + character_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + item_id VARCHAR(64) NOT NULL REFERENCES items(id), + slot_type VARCHAR(16) NOT NULL DEFAULT 'bag', -- bag / warehouse / mail / auction_escrow + quantity INT NOT NULL DEFAULT 1, + instance_data JSONB NOT NULL DEFAULT '{}', + is_stolen BOOLEAN NOT NULL DEFAULT false, + blood_debt_mark BOOLEAN NOT NULL DEFAULT false, + can_trade BOOLEAN NOT NULL DEFAULT true, + acquired_at TIMESTAMPTZ DEFAULT NOW(), + created_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE INDEX idx_inventories_character_slot ON inventories(character_id, slot_type); +CREATE INDEX idx_inventories_item ON inventories(item_id); +CREATE INDEX idx_inventories_instance_gin ON inventories USING GIN (instance_data jsonb_path_ops); + +CREATE TABLE IF NOT EXISTS equipments ( + character_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + slot_name VARCHAR(32) NOT NULL, -- weapon / head / body / hand / foot / accessory1 / accessory2 / life_item + inventory_id UUID REFERENCES inventories(id) ON DELETE SET NULL, + updated_at TIMESTAMPTZ DEFAULT NOW(), + PRIMARY KEY (character_id, slot_name) +); + +CREATE INDEX idx_equipments_inventory ON equipments(inventory_id); + +CREATE TABLE IF NOT EXISTS currencies ( + code VARCHAR(32) PRIMARY KEY, + name VARCHAR(64) NOT NULL, + world_tier SMALLINT NOT NULL DEFAULT 1, + is_premium BOOLEAN NOT NULL DEFAULT false, + exchange_rules JSONB NOT NULL DEFAULT '{}' +); + +CREATE TABLE IF NOT EXISTS currency_balances ( + character_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + currency_code VARCHAR(32) NOT NULL REFERENCES currencies(code), + amount NUMERIC(20,4) NOT NULL DEFAULT 0, + total_earned NUMERIC(20,4) NOT NULL DEFAULT 0, + total_spent NUMERIC(20,4) NOT NULL DEFAULT 0, + updated_at TIMESTAMPTZ DEFAULT NOW(), + PRIMARY KEY (character_id, currency_code) +); + +-- 经济审计日志(建议按 created_at 月分区,保留 12 个月) +CREATE TABLE IF NOT EXISTS economy_audit_logs ( + id BIGSERIAL PRIMARY KEY, + character_id UUID REFERENCES characters(id) ON DELETE SET NULL, + entity_type VARCHAR(16) NOT NULL, -- character / guild / system + entity_id UUID NOT NULL, + currency_code VARCHAR(32) NOT NULL, + flow_type VARCHAR(16) NOT NULL, -- faucet / sink / transfer + reason_code VARCHAR(64) NOT NULL, + amount NUMERIC(20,4) NOT NULL, + balance_after NUMERIC(20,4), + related_id UUID, + world_tier SMALLINT NOT NULL, + created_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE INDEX idx_economy_audit_character_reason ON economy_audit_logs(character_id, reason_code, created_at); +CREATE INDEX idx_economy_audit_entity ON economy_audit_logs(entity_id, created_at); +CREATE INDEX idx_economy_audit_currency ON economy_audit_logs(currency_code, created_at); +CREATE INDEX idx_economy_audit_flow ON economy_audit_logs(flow_type, created_at); +CREATE INDEX idx_economy_audit_world_tier ON economy_audit_logs(world_tier, created_at); +CREATE INDEX idx_economy_audit_created ON economy_audit_logs(created_at); +COMMENT ON TABLE economy_audit_logs IS '大表建议:按 created_at 月分区,保留 12 个月(可用 pg_partman)'; + +-------------------------------------------------------------------------------- +-- 5. 组织(门派/帮派/家族/自建宗门) +-------------------------------------------------------------------------------- + +CREATE TABLE IF NOT EXISTS guilds ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + name VARCHAR(128) UNIQUE NOT NULL, + org_type VARCHAR(16) NOT NULL, -- system_sect / player_sect / guild / family + world_tier SMALLINT NOT NULL DEFAULT 1, + region_id UUID, + zone_id UUID, + leader_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + level SMALLINT NOT NULL DEFAULT 1, + reputation INT NOT NULL DEFAULT 0, + member_limit INT NOT NULL DEFAULT 50, + tax_rate NUMERIC(5,4) NOT NULL DEFAULT 0.20, + diplomacy_policy JSONB NOT NULL DEFAULT '{}', + building_levels JSONB NOT NULL DEFAULT '{}', + funds JSONB NOT NULL DEFAULT '{}', + status VARCHAR(16) NOT NULL DEFAULT 'active', -- active / dissolved / blacklisted + created_at TIMESTAMPTZ DEFAULT NOW(), + dissolved_at TIMESTAMPTZ +); + +CREATE INDEX idx_guilds_type_status ON guilds(org_type, status); +CREATE INDEX idx_guilds_world_tier ON guilds(world_tier, status); +CREATE INDEX idx_guilds_leader ON guilds(leader_id); + +CREATE TABLE IF NOT EXISTS guild_members ( + guild_id UUID NOT NULL REFERENCES guilds(id) ON DELETE CASCADE, + character_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + role VARCHAR(32) NOT NULL DEFAULT 'member', -- leader / vice / elder / elder_council / member / disciple_manager + joined_at TIMESTAMPTZ DEFAULT NOW(), + contribution JSONB NOT NULL DEFAULT '{}', + daily_quota JSONB NOT NULL DEFAULT '{}', + updated_at TIMESTAMPTZ DEFAULT NOW(), + PRIMARY KEY (guild_id, character_id) +); + +CREATE INDEX idx_guild_members_character ON guild_members(character_id); + +CREATE TABLE IF NOT EXISTS guild_territories ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + guild_id UUID NOT NULL REFERENCES guilds(id) ON DELETE CASCADE, + territory_type VARCHAR(32) NOT NULL, + level SMALLINT NOT NULL DEFAULT 1, + upgrade_progress JSONB NOT NULL DEFAULT '{}', + params JSONB NOT NULL DEFAULT '{}', + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE INDEX idx_guild_territories_guild ON guild_territories(guild_id, territory_type); + +CREATE TABLE IF NOT EXISTS guild_diplomacy ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + guild_a_id UUID NOT NULL REFERENCES guilds(id) ON DELETE CASCADE, + guild_b_id UUID NOT NULL REFERENCES guilds(id) ON DELETE CASCADE, + relation VARCHAR(16) NOT NULL, -- allied / at_war / trade / betrayed_cooldown + started_at TIMESTAMPTZ DEFAULT NOW(), + ended_at TIMESTAMPTZ +); + +CREATE INDEX idx_guild_diplomacy_a ON guild_diplomacy(guild_a_id, relation); +CREATE INDEX idx_guild_diplomacy_b ON guild_diplomacy(guild_b_id, relation); + +CREATE TABLE IF NOT EXISTS guild_warehouses ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + guild_id UUID NOT NULL REFERENCES guilds(id) ON DELETE CASCADE, + inventory_id UUID NOT NULL REFERENCES inventories(id) ON DELETE CASCADE, + deposited_by UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + deposit_type VARCHAR(16) NOT NULL DEFAULT 'common', -- common / tribute / black_eat + created_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE INDEX idx_guild_warehouses_guild ON guild_warehouses(guild_id); + +-------------------------------------------------------------------------------- +-- 6. 市场、拍卖与情报 +-------------------------------------------------------------------------------- + +CREATE TABLE IF NOT EXISTS market_orders ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + seller_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + seller_guild_id UUID REFERENCES guilds(id) ON DELETE SET NULL, + item_id VARCHAR(64) NOT NULL REFERENCES items(id), + inventory_id UUID NOT NULL REFERENCES inventories(id) ON DELETE CASCADE, + currency_code VARCHAR(32) NOT NULL REFERENCES currencies(code), + unit_price NUMERIC(20,4) NOT NULL, + quantity INT NOT NULL, + total_price NUMERIC(20,4) NOT NULL, + tax_rate NUMERIC(5,4) NOT NULL DEFAULT 0.05, + status VARCHAR(16) NOT NULL DEFAULT 'active', -- active / sold / cancelled / expired + world_tier SMALLINT NOT NULL DEFAULT 1, + listed_at TIMESTAMPTZ DEFAULT NOW(), + expired_at TIMESTAMPTZ, + sold_at TIMESTAMPTZ, + buyer_id UUID REFERENCES characters(id) ON DELETE SET NULL +); + +CREATE INDEX idx_market_orders_search ON market_orders(item_id, status, world_tier); +CREATE INDEX idx_market_orders_seller ON market_orders(seller_id, status); +CREATE INDEX idx_market_orders_listed ON market_orders(listed_at); +CREATE INDEX idx_market_orders_status ON market_orders(status, expired_at); +COMMENT ON TABLE market_orders IS '大表建议:按 listed_at 月分区,保留 6 个月'; + +CREATE TABLE IF NOT EXISTS auctions ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + seller_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + guild_id UUID REFERENCES guilds(id) ON DELETE SET NULL, + auction_type VARCHAR(16) NOT NULL, -- official / organization + item_id VARCHAR(64) NOT NULL REFERENCES items(id), + inventory_id UUID NOT NULL REFERENCES inventories(id) ON DELETE CASCADE, + category VARCHAR(32) NOT NULL, -- rare_bloodline / rare_manual / jade_slip / secret_material / artifact / material + currency_code VARCHAR(32) NOT NULL REFERENCES currencies(code), + start_price NUMERIC(20,4) NOT NULL, + reserve_price NUMERIC(20,4), + min_increment_rate NUMERIC(5,4) NOT NULL DEFAULT 0.05, + deposit_rate NUMERIC(5,4) NOT NULL DEFAULT 0.05, + tax_rate NUMERIC(5,4) NOT NULL DEFAULT 0.05, + status VARCHAR(16) NOT NULL DEFAULT 'preparing', -- preparing / active / extended / sold / expired / robbed + started_at TIMESTAMPTZ, + ended_at TIMESTAMPTZ, + is_anonymous BOOLEAN NOT NULL DEFAULT false, + access_type VARCHAR(16) NOT NULL DEFAULT 'public', + risk_type VARCHAR(16) NOT NULL DEFAULT 'none', -- rare_robbable / none + created_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE INDEX idx_auctions_list ON auctions(status, auction_type, ended_at); +CREATE INDEX idx_auctions_seller ON auctions(seller_id); +CREATE INDEX idx_auctions_started ON auctions(started_at); +CREATE INDEX idx_auctions_guild ON auctions(guild_id, status); + +CREATE TABLE IF NOT EXISTS auction_bids ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + auction_id UUID NOT NULL REFERENCES auctions(id) ON DELETE CASCADE, + bidder_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + amount NUMERIC(20,4) NOT NULL, + deposit_paid NUMERIC(20,4) NOT NULL DEFAULT 0, + is_auto_bid BOOLEAN NOT NULL DEFAULT false, + auto_max_amount NUMERIC(20,4), + bid_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE INDEX idx_auction_bids_auction ON auction_bids(auction_id, bid_at); +CREATE INDEX idx_auction_bids_bidder ON auction_bids(bidder_id, bid_at); +COMMENT ON TABLE auction_bids IS '大表建议:与 auctions 对齐,按 bid_at 月分区,保留 6 个月'; + +CREATE TABLE IF NOT EXISTS auction_blacklist_records ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + guild_id UUID NOT NULL REFERENCES guilds(id) ON DELETE CASCADE, + auction_id UUID NOT NULL REFERENCES auctions(id) ON DELETE CASCADE, + is_exposed BOOLEAN NOT NULL DEFAULT false, + exposed_at TIMESTAMPTZ, + exposure_type VARCHAR(16), -- report / arbitration / heaven_sense + punishment_level SMALLINT, + reputation_delta INT, + created_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE INDEX idx_auction_blacklist_guild ON auction_blacklist_records(guild_id); + +CREATE TABLE IF NOT EXISTS intelligence_orders ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + seller_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + buyer_id UUID REFERENCES characters(id) ON DELETE SET NULL, + intel_type VARCHAR(32) NOT NULL, -- resource / event / location / bounty_clue / instance_entry / unique_skill_clue + target_id UUID, + target_world_tier SMALLINT NOT NULL DEFAULT 1, + content_summary VARCHAR(256), + detail_data JSONB NOT NULL DEFAULT '{}', + currency_code VARCHAR(32) NOT NULL REFERENCES currencies(code), + price NUMERIC(20,4) NOT NULL, + purchase_count SMALLINT NOT NULL DEFAULT 0, + max_purchase SMALLINT NOT NULL DEFAULT 1, + status VARCHAR(16) NOT NULL DEFAULT 'active', -- active / sold_out / expired + cooldown_until TIMESTAMPTZ, + created_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE INDEX idx_intelligence_type ON intelligence_orders(intel_type, status); +CREATE INDEX idx_intelligence_target_tier ON intelligence_orders(target_world_tier, status); +CREATE INDEX idx_intelligence_seller ON intelligence_orders(seller_id); +CREATE INDEX idx_intelligence_created ON intelligence_orders(created_at); + +-------------------------------------------------------------------------------- +-- 7. 弟子系统 +-------------------------------------------------------------------------------- + +CREATE TABLE IF NOT EXISTS disciples ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + owner_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + guild_id UUID REFERENCES guilds(id) ON DELETE SET NULL, + name VARCHAR(64) NOT NULL, + race_id VARCHAR(32) NOT NULL, + quality VARCHAR(16) NOT NULL DEFAULT 'common', -- common / fine / excellent / perfect / immortal + profession VARCHAR(32), + stats JSONB NOT NULL DEFAULT '{}', + skills JSONB NOT NULL DEFAULT '{}', + equipment JSONB NOT NULL DEFAULT '{}', + daily_task_quota_min INT NOT NULL DEFAULT 120, + death_rate_modifier NUMERIC(5,4) NOT NULL DEFAULT 0, + status VARCHAR(16) NOT NULL DEFAULT 'active', -- active / dead / dispatched / insurance_pending + tombstone_data JSONB NOT NULL DEFAULT '{}', + created_at TIMESTAMPTZ DEFAULT NOW(), + died_at TIMESTAMPTZ +); + +CREATE INDEX idx_disciples_owner ON disciples(owner_id, status); +CREATE INDEX idx_disciples_guild ON disciples(guild_id); + +CREATE TABLE IF NOT EXISTS disciple_missions ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + disciple_id UUID NOT NULL REFERENCES disciples(id) ON DELETE CASCADE, + owner_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + contract_id UUID, -- FK deferred to contracts creation below + mission_type VARCHAR(16) NOT NULL, -- mercenary / gathering / sect_proxy + difficulty SMALLINT NOT NULL DEFAULT 1, + success_rate NUMERIC(5,4) NOT NULL DEFAULT 0, + death_rate NUMERIC(5,4) NOT NULL DEFAULT 0, + insurance_item_id UUID REFERENCES inventories(id) ON DELETE SET NULL, + result VARCHAR(16) NOT NULL DEFAULT 'pending', -- pending / success / fail / death + rewards JSONB NOT NULL DEFAULT '{}', + started_at TIMESTAMPTZ DEFAULT NOW(), + ended_at TIMESTAMPTZ +); + +CREATE INDEX idx_disciple_missions_disciple ON disciple_missions(disciple_id, result); +CREATE INDEX idx_disciple_missions_owner ON disciple_missions(owner_id, started_at); + +-------------------------------------------------------------------------------- +-- 8. 悬赏、追杀令与佣兵委托 +-------------------------------------------------------------------------------- + +CREATE TABLE IF NOT EXISTS contracts ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + contract_type VARCHAR(32) NOT NULL, -- mercenary / limited_time / bounty + publisher_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + publisher_guild_id UUID REFERENCES guilds(id) ON DELETE SET NULL, + difficulty SMALLINT NOT NULL DEFAULT 1, + currency_code VARCHAR(32) NOT NULL REFERENCES currencies(code), + base_reward NUMERIC(20,4) NOT NULL, + max_participants SMALLINT NOT NULL DEFAULT 1, + status VARCHAR(16) NOT NULL DEFAULT 'active', -- active / accepted / completed / failed / expired / cancelled + valid_until TIMESTAMPTZ NOT NULL, + created_at TIMESTAMPTZ DEFAULT NOW(), + completed_at TIMESTAMPTZ +); + +CREATE INDEX idx_contracts_publisher ON contracts(publisher_id, contract_type, status); +CREATE INDEX idx_contracts_status_until ON contracts(status, valid_until); + +CREATE TABLE IF NOT EXISTS bounties ( + contract_id UUID PRIMARY KEY REFERENCES contracts(id) ON DELETE CASCADE, + bounty_type VARCHAR(16) NOT NULL, -- official_bounty / private_bounty / manhunt + target_id UUID REFERENCES characters(id) ON DELETE CASCADE, + target_world_tier SMALLINT NOT NULL DEFAULT 1, + reward_amount NUMERIC(20,4) NOT NULL, + fee_amount NUMERIC(20,4) NOT NULL DEFAULT 0, + is_anonymous BOOLEAN NOT NULL DEFAULT false, + report_count_today SMALLINT NOT NULL DEFAULT 0, + trigger_probability NUMERIC(5,4) NOT NULL DEFAULT 0, + clues JSONB NOT NULL DEFAULT '{}', + item_inventory_id UUID REFERENCES inventories(id) ON DELETE SET NULL +); + +CREATE INDEX idx_bounties_target ON bounties(target_id, bounty_type, target_world_tier); +CREATE INDEX idx_bounties_type ON bounties(bounty_type, target_world_tier); + +CREATE TABLE IF NOT EXISTS contract_participants ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + contract_id UUID NOT NULL REFERENCES contracts(id) ON DELETE CASCADE, + character_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + participant_type VARCHAR(16) NOT NULL, -- hunter / disciple_proxy / party_member + disciple_id UUID REFERENCES disciples(id) ON DELETE SET NULL, + status VARCHAR(16) NOT NULL DEFAULT 'accepted', -- accepted / active / completed / failed + accepted_at TIMESTAMPTZ DEFAULT NOW(), + completed_at TIMESTAMPTZ +); + +CREATE INDEX idx_contract_participants_contract ON contract_participants(contract_id, status); +CREATE INDEX idx_contract_participants_character ON contract_participants(character_id, status); + +CREATE TABLE IF NOT EXISTS manhunt_records ( + bounty_id UUID PRIMARY KEY REFERENCES bounties(contract_id) ON DELETE CASCADE, + original_owner_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + current_holder_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + window_end_at TIMESTAMPTZ NOT NULL, + outcome VARCHAR(16) NOT NULL DEFAULT 'pending', -- pending / returned / black_ate / failed + hunter_choice VARCHAR(16), + compensation_paid NUMERIC(20,4) DEFAULT 0, + chase_right_until TIMESTAMPTZ, + created_at TIMESTAMPTZ DEFAULT NOW() +); + +-------------------------------------------------------------------------------- +-- 9. 世界地图、区域、副本与遗迹 +-------------------------------------------------------------------------------- + +CREATE TABLE IF NOT EXISTS world_layers ( + tier SMALLINT PRIMARY KEY, + name VARCHAR(64) NOT NULL, + display_layer SMALLINT NOT NULL DEFAULT 0, + realm_tier SMALLINT NOT NULL DEFAULT 1, + is_pvp_enabled BOOLEAN NOT NULL DEFAULT false, + cross_tier_rules JSONB NOT NULL DEFAULT '{}' +); + +CREATE TABLE IF NOT EXISTS maps ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + world_tier SMALLINT NOT NULL REFERENCES world_layers(tier), + name VARCHAR(128) NOT NULL, + map_type VARCHAR(16) NOT NULL DEFAULT 'world', -- world / event / instance / ruin + seed BIGINT, + layout_data JSONB NOT NULL DEFAULT '{}', + is_active BOOLEAN NOT NULL DEFAULT true, + created_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE INDEX idx_maps_world_tier ON maps(world_tier, map_type, is_active); + +CREATE TABLE IF NOT EXISTS regions ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + map_id UUID NOT NULL REFERENCES maps(id) ON DELETE CASCADE, + world_tier SMALLINT NOT NULL DEFAULT 1, + name VARCHAR(128) NOT NULL, + theme VARCHAR(32), + is_safe_zone BOOLEAN NOT NULL DEFAULT false, + pvp_rules JSONB NOT NULL DEFAULT '{}' +); + +CREATE INDEX idx_regions_map ON regions(map_id, is_safe_zone); +CREATE INDEX idx_regions_world_tier ON regions(world_tier); + +CREATE TABLE IF NOT EXISTS zones ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + region_id UUID NOT NULL REFERENCES regions(id) ON DELETE CASCADE, + zone_type VARCHAR(16) NOT NULL, -- stronghold / wild / secret / dungeon / ruins + name VARCHAR(128) NOT NULL, + terrain VARCHAR(32), + weather VARCHAR(32), + resource_density SMALLINT NOT NULL DEFAULT 1, + danger_level SMALLINT NOT NULL DEFAULT 1, + rarity VARCHAR(16) NOT NULL DEFAULT 'normal', + seed BIGINT, + generated_data JSONB NOT NULL DEFAULT '{}', + refreshed_at TIMESTAMPTZ DEFAULT NOW(), + expires_at TIMESTAMPTZ +); + +CREATE INDEX idx_zones_region ON zones(region_id, zone_type); +CREATE INDEX idx_zones_expires ON zones(expires_at); + +CREATE TABLE IF NOT EXISTS zone_explorations ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + zone_id UUID NOT NULL REFERENCES zones(id) ON DELETE CASCADE, + character_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + fog_state JSONB NOT NULL DEFAULT '{}', + exploration_count INT NOT NULL DEFAULT 0, + last_entered_at TIMESTAMPTZ, + UNIQUE (zone_id, character_id) +); + +CREATE INDEX idx_zone_explorations_zone ON zone_explorations(zone_id); +CREATE INDEX idx_zone_explorations_character ON zone_explorations(character_id); + +-------------------------------------------------------------------------------- +-- 10. 战斗与战报 +-------------------------------------------------------------------------------- + +CREATE TABLE IF NOT EXISTS battles ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + battle_type VARCHAR(16) NOT NULL, -- expedition_pve / dungeon_pve / pvp / gvg / bounty / manhunt + world_tier SMALLINT NOT NULL DEFAULT 1, + realm_tier SMALLINT NOT NULL DEFAULT 1, + game_timestamp TIMESTAMPTZ DEFAULT NOW(), + attacker_id UUID REFERENCES characters(id) ON DELETE SET NULL, + defender_id UUID REFERENCES characters(id) ON DELETE SET NULL, + party_a UUID[] NOT NULL DEFAULT '{}', + party_b UUID[] NOT NULL DEFAULT '{}', + status VARCHAR(16) NOT NULL DEFAULT 'in_progress', -- in_progress / completed + result_summary JSONB NOT NULL DEFAULT '{}', + created_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE INDEX idx_battles_attacker ON battles(attacker_id, created_at); +CREATE INDEX idx_battles_defender ON battles(defender_id, created_at); +CREATE INDEX idx_battles_type_status ON battles(battle_type, status); +CREATE INDEX idx_battles_realm ON battles(world_tier, realm_tier, created_at); + +CREATE TABLE IF NOT EXISTS battle_logs ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + battle_id UUID UNIQUE NOT NULL REFERENCES battles(id) ON DELETE CASCADE, + report JSONB NOT NULL DEFAULT '{}', + special_events JSONB NOT NULL DEFAULT '[]', + drops JSONB NOT NULL DEFAULT '{}', + created_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE INDEX idx_battle_logs_created ON battle_logs(created_at); +CREATE INDEX idx_battle_logs_report_gin ON battle_logs USING GIN (report jsonb_path_ops); +COMMENT ON TABLE battle_logs IS '大表建议:按 created_at 周分区,保留 8 周(可用 pg_partman)'; + +CREATE TABLE IF NOT EXISTS player_kills ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + killer_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + victim_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + battle_id UUID REFERENCES battles(id) ON DELETE SET NULL, + world_tier SMALLINT NOT NULL DEFAULT 1, + is_malice BOOLEAN NOT NULL DEFAULT false, + karma_delta INT NOT NULL DEFAULT 0, + crime_delta INT NOT NULL DEFAULT 0, + loot_taken JSONB NOT NULL DEFAULT '{}', + created_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE INDEX idx_player_kills_killer ON player_kills(killer_id); +CREATE INDEX idx_player_kills_victim ON player_kills(victim_id); +CREATE INDEX idx_player_kills_world ON player_kills(world_tier, created_at); + +-------------------------------------------------------------------------------- +-- 11. 副本、遗迹(依赖 battles) +-------------------------------------------------------------------------------- + +CREATE TABLE IF NOT EXISTS instances ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + zone_id UUID NOT NULL REFERENCES zones(id) ON DELETE CASCADE, + instance_type VARCHAR(16) NOT NULL, -- permanent / random / ruin / event + theme VARCHAR(32), + world_tier SMALLINT NOT NULL DEFAULT 1, + recommended_realm_tier SMALLINT NOT NULL DEFAULT 1, + generated_layout JSONB NOT NULL DEFAULT '{}', + affixes JSONB NOT NULL DEFAULT '[]', + max_parties SMALLINT NOT NULL DEFAULT 1, + expires_at TIMESTAMPTZ, + created_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE INDEX idx_instances_world_tier ON instances(world_tier, instance_type, expires_at); +CREATE INDEX idx_instances_zone ON instances(zone_id); + +CREATE TABLE IF NOT EXISTS instance_runs ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + instance_id UUID NOT NULL REFERENCES instances(id) ON DELETE CASCADE, + party_leader_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + party_members UUID[] NOT NULL DEFAULT '{}', + difficulty_coefficient NUMERIC(6,4) NOT NULL DEFAULT 1.0, + status VARCHAR(16) NOT NULL DEFAULT 'in_progress', -- in_progress / completed / failed / abandoned + battle_id UUID REFERENCES battles(id) ON DELETE SET NULL, + consumed_keys SMALLINT NOT NULL DEFAULT 0, + started_at TIMESTAMPTZ DEFAULT NOW(), + ended_at TIMESTAMPTZ +); + +CREATE INDEX idx_instance_runs_instance ON instance_runs(instance_id, status); +CREATE INDEX idx_instance_runs_leader ON instance_runs(party_leader_id, started_at); + +CREATE TABLE IF NOT EXISTS instance_loot ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + run_id UUID NOT NULL REFERENCES instance_runs(id) ON DELETE CASCADE, + character_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + item_id VARCHAR(64) NOT NULL REFERENCES items(id), + inventory_id UUID REFERENCES inventories(id) ON DELETE SET NULL, + currency_code VARCHAR(32) REFERENCES currencies(code), + currency_amount NUMERIC(20,4) DEFAULT 0, + is_resonance_copy BOOLEAN NOT NULL DEFAULT false, + completeness NUMERIC(5,4) DEFAULT 1.0, + created_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE INDEX idx_instance_loot_run ON instance_loot(run_id); +CREATE INDEX idx_instance_loot_character ON instance_loot(character_id); + +CREATE TABLE IF NOT EXISTS world_ruin_records ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + source_character_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + source_world_tier SMALLINT NOT NULL, + region_id UUID NOT NULL REFERENCES regions(id) ON DELETE CASCADE, + zone_id UUID NOT NULL REFERENCES zones(id) ON DELETE CASCADE, + instance_id UUID REFERENCES instances(id) ON DELETE SET NULL, + richness_score NUMERIC(8,2) NOT NULL DEFAULT 0, + snapshot_data JSONB NOT NULL DEFAULT '{}', + total_extractable NUMERIC(6,4) NOT NULL DEFAULT 0, + extracted_ratio NUMERIC(6,4) NOT NULL DEFAULT 0, + status VARCHAR(16) NOT NULL DEFAULT 'active', + opened_at TIMESTAMPTZ DEFAULT NOW(), + expires_at TIMESTAMPTZ +); + +CREATE INDEX idx_world_ruin_source ON world_ruin_records(source_character_id); +CREATE INDEX idx_world_ruin_region ON world_ruin_records(region_id, status); +CREATE INDEX idx_world_ruin_expires ON world_ruin_records(status, expires_at); + +-------------------------------------------------------------------------------- +-- 12. 渡劫记录 +-------------------------------------------------------------------------------- + +CREATE TABLE IF NOT EXISTS tribulation_records ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + character_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + realm_tier SMALLINT NOT NULL, + minor_realm SMALLINT NOT NULL, + tribulation_type VARCHAR(16) NOT NULL, -- normal / heart_devil / qi_deviation / chaos / heti + base_success_rate NUMERIC(5,4) NOT NULL, + modified_success_rate NUMERIC(5,4) NOT NULL, + helper_ids UUID[] NOT NULL DEFAULT '{}', + result VARCHAR(16) NOT NULL, -- success / fail / backlash / death + penalties JSONB NOT NULL DEFAULT '{}', + drops_on_success JSONB NOT NULL DEFAULT '[]', + san_snapshot SMALLINT NOT NULL DEFAULT 100, + created_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE INDEX idx_tribulation_character ON tribulation_records(character_id, created_at); +CREATE INDEX idx_tribulation_realm ON tribulation_records(realm_tier, created_at); + +-------------------------------------------------------------------------------- +-- 13. 社交关系 +-------------------------------------------------------------------------------- + +CREATE TABLE IF NOT EXISTS social_relations ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + character_a_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + character_b_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + relation_type VARCHAR(16) NOT NULL, -- friend / companion / master / apprentice / enemy + intimacy INT NOT NULL DEFAULT 0, + status VARCHAR(16) NOT NULL DEFAULT 'active', -- active / cooldown / dissolved + cooldown_until TIMESTAMPTZ, + created_at TIMESTAMPTZ DEFAULT NOW(), + dissolved_at TIMESTAMPTZ, + UNIQUE (character_a_id, character_b_id, relation_type) +); + +CREATE INDEX idx_social_relations_a ON social_relations(character_a_id, relation_type, status); +CREATE INDEX idx_social_relations_b ON social_relations(character_b_id, relation_type, status); + +CREATE TABLE IF NOT EXISTS lovers ( + relation_id UUID PRIMARY KEY REFERENCES social_relations(id) ON DELETE CASCADE, + resonance INT NOT NULL DEFAULT 0, + shared_residence_id UUID REFERENCES guild_territories(id) ON DELETE SET NULL, + combined_skill_id UUID REFERENCES character_skills(id) ON DELETE SET NULL, + vow_path VARCHAR(16), + teleport_cooldown_until TIMESTAMPTZ, + mutual_benefits JSONB NOT NULL DEFAULT '{}', + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE TABLE IF NOT EXISTS sworn_brothers ( + relation_id UUID PRIMARY KEY REFERENCES social_relations(id) ON DELETE CASCADE, + group_id UUID UNIQUE NOT NULL DEFAULT gen_random_uuid(), + member_order SMALLINT NOT NULL DEFAULT 0, + shared_mission_slots JSONB NOT NULL DEFAULT '{}', + group_buffs JSONB NOT NULL DEFAULT '{}', + flag_zone_id UUID REFERENCES zones(id) ON DELETE SET NULL, + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE TABLE IF NOT EXISTS reputation_records ( + id BIGSERIAL PRIMARY KEY, + character_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + source_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + source_type VARCHAR(16) NOT NULL, -- trade / mercenary / master / party / report + delta INT NOT NULL DEFAULT 0, + tag VARCHAR(32), + created_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE INDEX idx_reputation_character ON reputation_records(character_id, created_at); +CREATE INDEX idx_reputation_source ON reputation_records(source_id, created_at); +COMMENT ON TABLE reputation_records IS '大表建议:按 created_at 月分区,保留 6 个月'; + +-------------------------------------------------------------------------------- +-- 14. 配置与审计 +-------------------------------------------------------------------------------- + +CREATE TABLE IF NOT EXISTS nacos_configs ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + config_key VARCHAR(128) UNIQUE NOT NULL, + namespace VARCHAR(64) NOT NULL, + value JSONB NOT NULL DEFAULT '{}', + version INT NOT NULL DEFAULT 1, + is_grayscale BOOLEAN NOT NULL DEFAULT false, + grayscale_ratio NUMERIC(5,4) NOT NULL DEFAULT 0, + effective_from TIMESTAMPTZ, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE INDEX idx_nacos_configs_namespace ON nacos_configs(namespace, config_key); + +CREATE TABLE IF NOT EXISTS daily_reset_tracking ( + character_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + reset_date DATE NOT NULL, + report_count_used SMALLINT NOT NULL DEFAULT 0, + instance_count_used SMALLINT NOT NULL DEFAULT 0, + ruin_count_used SMALLINT NOT NULL DEFAULT 0, + double_cultivation_minutes SMALLINT NOT NULL DEFAULT 0, + fishing_games SMALLINT NOT NULL DEFAULT 0, + updated_at TIMESTAMPTZ DEFAULT NOW(), + PRIMARY KEY (character_id, reset_date) +); + +-------------------------------------------------------------------------------- +-- 14. 延迟外键约束(解决建表顺序依赖) +-------------------------------------------------------------------------------- +ALTER TABLE guilds ADD CONSTRAINT fk_guilds_region + FOREIGN KEY (region_id) REFERENCES regions(id) ON DELETE SET NULL; +ALTER TABLE guilds ADD CONSTRAINT fk_guilds_zone + FOREIGN KEY (zone_id) REFERENCES zones(id) ON DELETE SET NULL; + +ALTER TABLE disciple_missions ADD CONSTRAINT fk_disciple_missions_contract + FOREIGN KEY (contract_id) REFERENCES contracts(id) ON DELETE SET NULL; + +-------------------------------------------------------------------------------- +-- 15. 参考数据 seed +-------------------------------------------------------------------------------- + +INSERT INTO race_templates (id, name, category, can_create, description) VALUES +('human', '人族', 'common', false, '默认不可创建,可通过转化获得'), +('tiger_yao', '虎妖', 'common', true, '妖族分支'), +('wolf_yao', '狼妖', 'common', true, '妖族分支'), +('elf_light', '光精灵', 'common', true, '精灵族分支'), +('elf_dark', '暗精灵', 'common', true, '精灵族分支'), +('demon_blood', '魔血族', 'common', true, '魔族分支'), +('ghost_ethereal', '幽魂族', 'common', true, '鬼族分支'), +('deep_one', '深潜裔', 'rare', true, '稀有血统,多分支进化'), +('dragon_blood', '龙血族', 'rare', true, '稀有种族'), +('chaos_heritage', '混沌裔', 'rare', true, '稀有种族'), +('giant', '巨人族', 'rare', true, '稀有种族') +ON CONFLICT (id) DO NOTHING; + +INSERT INTO realms (tier, minor_realm_max, name, world_tier, main_currency_code, is_tribulation_required, base_success_rate, attr_growth_template) VALUES +(1, 3, '炼气期', 1, 'copper', false, 1.0, '{"hp":10,"atk":2,"def":1}'), +(2, 3, '筑基期', 2, 'copper', true, 0.55, '{"hp":20,"atk":4,"def":2}'), +(3, 3, '金丹期', 3, 'spirit_stone_low', true, 0.50, '{"hp":35,"atk":7,"def":4}'), +(4, 3, '元婴期', 4, 'soul_crystal', true, 0.45, '{"hp":55,"atk":11,"def":6}'), +(5, 3, '化神期', 5, 'immortal_crystal', true, 0.40, '{"hp":80,"atk":16,"def":9}'), +(6, 3, '合体期', 6, 'chaos_crystal', true, 0.35, '{"hp":110,"atk":22,"def":12}') +ON CONFLICT (tier) DO NOTHING; + +INSERT INTO world_layers (tier, name, display_layer, realm_tier, is_pvp_enabled, cross_tier_rules) VALUES +(1, '种族出生地', 0, 1, false, '{}'), +(2, '洪荒主陆', 1, 2, true, '{}'), +(3, '洪荒腹地', 2, 3, true, '{}'), +(4, '太古秘境', 3, 4, true, '{}'), +(5, '混沌之渊·化神域', 4, 5, true, '{}'), +(6, '混沌之渊·合体域', 5, 6, true, '{}') +ON CONFLICT (tier) DO NOTHING; + +INSERT INTO currencies (code, name, world_tier, is_premium, exchange_rules) VALUES +('copper', '铜钱', 1, false, '{}'), +('silver', '银两', 2, false, '{}'), +('spirit_stone_low', '下品灵石', 3, false, '{}'), +('spirit_stone_mid', '中品灵石', 3, false, '{}'), +('soul_crystal', '魂晶', 4, false, '{}'), +('immortal_crystal', '仙晶', 5, false, '{}'), +('chaos_crystal', '混沌灵石', 6, false, '{}'), +('purple_gas', '鸿蒙紫气', 1, true, '{}') +ON CONFLICT (code) DO NOTHING; + +-------------------------------------------------------------------------------- +-- 自检提示(可选): +-- psql -U postgres -d honghuang -f database/migrations/001_init_schema.up.sql +-------------------------------------------------------------------------------- diff --git a/database/migrations/002_expand_realms.up.sql b/database/migrations/002_expand_realms.up.sql new file mode 100644 index 0000000..1aff260 --- /dev/null +++ b/database/migrations/002_expand_realms.up.sql @@ -0,0 +1,215 @@ +-- T002: 扩展境界系统至9大境界(对齐GDD-02/GDD-08五层世界分层) +-- 更新realm模板数据,新增境界名称表 + +-- 1. 更新realms表数据为9大境界 +DELETE FROM realms; + +INSERT INTO realms (tier, minor_realm_max, name, world_tier, main_currency_code, is_tribulation_required, base_success_rate, attr_growth_template) VALUES +(1, 3, '炼气期', 1, 'copper', false, 1.0, '{"hp":10,"atk":2,"def":1}'), +(2, 3, '筑基期', 2, 'copper', true, 0.55, '{"hp":20,"atk":4,"def":2}'), +(3, 3, '金丹期', 2, 'spirit_stone_low', true, 0.50, '{"hp":35,"atk":7,"def":4}'), +(4, 3, '元婴期', 2, 'spirit_stone_mid', true, 0.45, '{"hp":55,"atk":11,"def":6}'), +(5, 3, '化神期', 3, 'soul_crystal', true, 0.40, '{"hp":80,"atk":16,"def":9}'), +(6, 3, '合体期', 3, 'soul_crystal', true, 0.35, '{"hp":110,"atk":22,"def":12}'), +(7, 3, '大乘期', 4, 'immortal_crystal', true, 0.30, '{"hp":150,"atk":30,"def":16}'), +(8, 3, '渡劫期', 4, 'immortal_crystal', true, 0.25, '{"hp":200,"atk":40,"def":22}'), +(9, 3, '飞升期', 5, 'chaos_crystal', true, 0.20, '{"hp":280,"atk":55,"def":30}') +ON CONFLICT (tier) DO UPDATE SET + name = EXCLUDED.name, + world_tier = EXCLUDED.world_tier, + main_currency_code = EXCLUDED.main_currency_code, + is_tribulation_required = EXCLUDED.is_tribulation_required, + base_success_rate = EXCLUDED.base_success_rate, + attr_growth_template = EXCLUDED.attr_growth_template; + +-- 2. 创建种族境界名称表 +CREATE TABLE IF NOT EXISTS realm_names ( + id SERIAL PRIMARY KEY, + realm_tier SMALLINT NOT NULL, + minor_realm SMALLINT NOT NULL, + race_id VARCHAR(32) NOT NULL, + name VARCHAR(64) NOT NULL, + description TEXT, + UNIQUE (realm_tier, minor_realm, race_id) +); + +-- 3. 人族境界名称(修仙路线 - 唯一) +INSERT INTO realm_names (realm_tier, minor_realm, race_id, name, description) VALUES +(1, 1, 'human', '炼气初期', '感应天地灵气,开始修炼'), +(1, 2, 'human', '炼气中期', '灵气在体内循环,内力初成'), +(1, 3, 'human', '炼气圆满', '灵气充盈全身,准备筑基'), +(2, 1, 'human', '筑基初期', '道基初成,修炼根基稳固'), +(2, 2, 'human', '筑基中期', '道基渐固,可修炼更高功法'), +(2, 3, 'human', '筑基圆满', '道基稳固,可尝试结丹'), +(3, 1, 'human', '金丹初期', '凝结金丹,质变提升'), +(3, 2, 'human', '金丹中期', '金丹稳固,内力大增'), +(3, 3, 'human', '金丹圆满', '金丹圆满,可尝试元婴'), +(4, 1, 'human', '元婴初期', '孕育元婴,神识觉醒'), +(4, 2, 'human', '元婴中期', '元婴成长,神识增强'), +(4, 3, 'human', '元婴圆满', '元婴圆满,可尝试化神'), +(5, 1, 'human', '化神初期', '化神出窍,超凡入圣'), +(5, 2, 'human', '化神中期', '神识大增,掌控天地'), +(5, 3, 'human', '化神圆满', '化神圆满,可尝试合体'), +(6, 1, 'human', '合体初期', '与天地合一,掌控法则'), +(6, 2, 'human', '合体中期', '法则领悟加深'), +(6, 3, 'human', '合体圆满', '合体圆满,可尝试渡劫'), +(7, 1, 'human', '大乘初期', '大乘圆满,准备飞升'), +(7, 2, 'human', '大乘中期', '大乘境界稳固'), +(7, 3, 'human', '大乘圆满', '大乘圆满,等待天劫'), +(8, 1, 'human', '渡劫初期', '开始渡劫,接受天道考验'), +(8, 2, 'human', '渡劫中期', '渡劫进行中'), +(8, 3, 'human', '渡劫圆满', '渡劫成功,准备飞升'), +(9, 1, 'human', '飞升初期', '飞升仙界,成就大道'), +(9, 2, 'human', '飞升中期', '仙界修行'), +(9, 3, 'human', '飞升圆满', '大道圆满,超脱轮回') +ON CONFLICT (realm_tier, minor_realm, race_id) DO UPDATE SET + name = EXCLUDED.name, + description = EXCLUDED.description; + +-- 4. 妖族血脉觉醒阶段名称 +INSERT INTO realm_names (realm_tier, minor_realm, race_id, name, description) VALUES +(1, 1, 'tiger_yao', '血脉苏醒', '感应血脉力量,妖力初显'), +(1, 2, 'tiger_yao', '血脉觉醒', '觉醒血脉天赋,实力提升'), +(1, 3, 'tiger_yao', '血脉进化', '血脉进化,获得新能力'), +(2, 1, 'tiger_yao', '化形初期', '可短暂化为人形'), +(2, 2, 'tiger_yao', '化形中期', '化形时间延长'), +(2, 3, 'tiger_yao', '化形圆满', '可自由化形'), +(3, 1, 'tiger_yao', '本体觉醒初期', '觉醒本体形态,实力大增'), +(3, 2, 'tiger_yao', '本体觉醒中期', '本体形态稳固'), +(3, 3, 'tiger_yao', '本体觉醒圆满', '本体圆满,可尝试更高境界'), +(4, 1, 'tiger_yao', '妖丹初期', '凝结妖丹,质变提升'), +(4, 2, 'tiger_yao', '妖丹中期', '妖丹稳固,妖力大增'), +(4, 3, 'tiger_yao', '妖丹圆满', '妖丹圆满,可尝试化形'), +(5, 1, 'tiger_yao', '化形大成', '化形完全掌控'), +(5, 2, 'tiger_yao', '化形圆满', '化形圆满'), +(5, 3, 'tiger_yao', '化形极致', '化形极致,可尝试更高境界'), +(6, 1, 'tiger_yao', '妖王初期', '成为妖王,统领一方'), +(6, 2, 'tiger_yao', '妖王中期', '妖王实力稳固'), +(6, 3, 'tiger_yao', '妖王圆满', '妖王圆满,可尝试妖帝'), +(7, 1, 'tiger_yao', '妖帝初期', '成为妖帝,威震八方'), +(7, 2, 'tiger_yao', '妖帝中期', '妖帝实力大增'), +(7, 3, 'tiger_yao', '妖帝圆满', '妖帝圆满,可尝试渡劫'), +(8, 1, 'tiger_yao', '渡劫初期', '开始渡劫,接受天道考验'), +(8, 2, 'tiger_yao', '渡劫中期', '渡劫进行中'), +(8, 3, 'tiger_yao', '渡劫圆满', '渡劫成功,准备飞升'), +(9, 1, 'tiger_yao', '飞升初期', '飞升妖界,成就大道'), +(9, 2, 'tiger_yao', '飞升中期', '妖界修行'), +(9, 3, 'tiger_yao', '飞升圆满', '大道圆满,超脱轮回') +ON CONFLICT (realm_tier, minor_realm, race_id) DO UPDATE SET + name = EXCLUDED.name, + description = EXCLUDED.description; + +-- 5. 神族法则领悟阶段名称 +INSERT INTO realm_names (realm_tier, minor_realm, race_id, name, description) VALUES +(1, 1, 'divine', '法则感知', '感应天地法则,神力初显'), +(1, 2, 'divine', '法则领悟', '领悟特定法则,实力提升'), +(1, 3, 'divine', '法则掌控', '掌控法则之力'), +(2, 1, 'divine', '神力凝聚', '凝聚神力,质变提升'), +(2, 2, 'divine', '神力稳固', '神力稳固,可修炼更高法则'), +(2, 3, 'divine', '神力圆满', '神力圆满,可尝试神格'), +(3, 1, 'divine', '神格初期', '凝聚神格,成就神位'), +(3, 2, 'divine', '神格中期', '神格稳固,神力大增'), +(3, 3, 'divine', '神格圆满', '神格圆满,可尝试更高境界'), +(4, 1, 'divine', '天神初期', '成为天神,掌控一方'), +(4, 2, 'divine', '天神中期', '天神实力稳固'), +(4, 3, 'divine', '天神圆满', '天神圆满,可尝试神王'), +(5, 1, 'divine', '神王初期', '成为神王,统领神族'), +(5, 2, 'divine', '神王中期', '神王实力大增'), +(5, 3, 'divine', '神王圆满', '神王圆满,可尝试神帝'), +(6, 1, 'divine', '神帝初期', '成为神帝,威震神界'), +(6, 2, 'divine', '神帝中期', '神帝实力大增'), +(6, 3, 'divine', '神帝圆满', '神帝圆满,可尝试渡劫'), +(7, 1, 'divine', '大乘初期', '大乘圆满,准备飞升'), +(7, 2, 'divine', '大乘中期', '大乘境界稳固'), +(7, 3, 'divine', '大乘圆满', '大乘圆满,等待天劫'), +(8, 1, 'divine', '渡劫初期', '开始渡劫,接受天道考验'), +(8, 2, 'divine', '渡劫中期', '渡劫进行中'), +(8, 3, 'divine', '渡劫圆满', '渡劫成功,准备飞升'), +(9, 1, 'divine', '飞升初期', '飞升神界,成就大道'), +(9, 2, 'divine', '飞升中期', '神界修行'), +(9, 3, 'divine', '飞升圆满', '大道圆满,超脱轮回') +ON CONFLICT (realm_tier, minor_realm, race_id) DO UPDATE SET + name = EXCLUDED.name, + description = EXCLUDED.description; + +-- 6. 巫族血肉淬炼阶段名称 +INSERT INTO realm_names (realm_tier, minor_realm, race_id, name, description) VALUES +(1, 1, 'witch', '淬体初期', '淬炼肉身,提升体质'), +(1, 2, 'witch', '淬体中期', '肉身强化,力量增长'), +(1, 3, 'witch', '淬体圆满', '淬体圆满,可尝试炼血'), +(2, 1, 'witch', '炼血初期', '炼化血脉,提升血脉强度'), +(2, 2, 'witch', '炼血中期', '血脉强化,巫力增长'), +(2, 3, 'witch', '炼血圆满', '炼血圆满,可尝试祖巫觉醒'), +(3, 1, 'witch', '祖巫觉醒初期', '觉醒祖巫真身,实力大增'), +(3, 2, 'witch', '祖巫觉醒中期', '祖巫真身稳固'), +(3, 3, 'witch', '祖巫觉醒圆满', '祖巫圆满,可尝试肉身成圣'), +(4, 1, 'witch', '肉身成圣初期', '肉身成圣,超凡入圣'), +(4, 2, 'witch', '肉身成圣中期', '肉身成圣稳固'), +(4, 3, 'witch', '肉身成圣圆满', '肉身成圣圆满,可尝试更高境界'), +(5, 1, 'witch', '祖巫大成', '祖巫真身大成,实力大增'), +(5, 2, 'witch', '祖巫圆满', '祖巫圆满'), +(5, 3, 'witch', '祖巫极致', '祖巫极致,可尝试更高境界'), +(6, 1, 'witch', '巫皇初期', '成为巫皇,统领巫族'), +(6, 2, 'witch', '巫皇中期', '巫皇实力稳固'), +(6, 3, 'witch', '巫皇圆满', '巫皇圆满,可尝试巫帝'), +(7, 1, 'witch', '巫帝初期', '成为巫帝,威震巫界'), +(7, 2, 'witch', '巫帝中期', '巫帝实力大增'), +(7, 3, 'witch', '巫帝圆满', '巫帝圆满,可尝试渡劫'), +(8, 1, 'witch', '渡劫初期', '开始渡劫,接受天道考验'), +(8, 2, 'witch', '渡劫中期', '渡劫进行中'), +(8, 3, 'witch', '渡劫圆满', '渡劫成功,准备飞升'), +(9, 1, 'witch', '飞升初期', '飞升巫界,成就大道'), +(9, 2, 'witch', '飞升中期', '巫界修行'), +(9, 3, 'witch', '飞升圆满', '大道圆满,超脱轮回') +ON CONFLICT (realm_tier, minor_realm, race_id) DO UPDATE SET + name = EXCLUDED.name, + description = EXCLUDED.description; + +-- 7. 深潜裔旧日铭印阶段名称 +INSERT INTO realm_names (realm_tier, minor_realm, race_id, name, description) VALUES +(1, 1, 'deep_spawn', '旧日低语', '听到旧日低语,SAN值开始波动'), +(1, 2, 'deep_spawn', '旧日铭印', '接受旧神铭印,获得邪能'), +(1, 3, 'deep_spawn', '疯狂觉醒', '疯狂觉醒,实力提升但SAN下降'), +(2, 1, 'deep_spawn', '邪能凝聚', '凝聚邪能,质变提升'), +(2, 2, 'deep_spawn', '邪能稳固', '邪能稳固,可修炼更高邪术'), +(2, 3, 'deep_spawn', '邪能圆满', '邪能圆满,可尝试旧神眷顾'), +(3, 1, 'deep_spawn', '旧神眷顾初期', '获得旧神眷顾,实力大增'), +(3, 2, 'deep_spawn', '旧神眷顾中期', '旧神眷顾稳固'), +(3, 3, 'deep_spawn', '旧神眷顾圆满', '旧神眷顾圆满,可尝试更高境界'), +(4, 1, 'deep_spawn', '域外邪能初期', '掌控域外邪能,超凡入圣'), +(4, 2, 'deep_spawn', '域外邪能中期', '域外邪能稳固'), +(4, 3, 'deep_spawn', '域外邪能圆满', '域外邪能圆满,可尝试更高境界'), +(5, 1, 'deep_spawn', '旧神化身初期', '化为旧神化身,实力大增'), +(5, 2, 'deep_spawn', '旧神化身中期', '旧神化身稳固'), +(5, 3, 'deep_spawn', '旧神化身圆满', '旧神化身圆满,可尝试更高境界'), +(6, 1, 'deep_spawn', '深渊领主初期', '成为深渊领主,统领一方'), +(6, 2, 'deep_spawn', '深渊领主中期', '深渊领主实力稳固'), +(6, 3, 'deep_spawn', '深渊领主圆满', '深渊领主圆满,可尝试更高境界'), +(7, 1, 'deep_spawn', '旧神降临初期', '旧神降临,实力大增'), +(7, 2, 'deep_spawn', '旧神降临中期', '旧神降临稳固'), +(7, 3, 'deep_spawn', '旧神降临圆满', '旧神降临圆满,可尝试渡劫'), +(8, 1, 'deep_spawn', '混沌渡劫初期', '开始混沌渡劫,接受旧神考验'), +(8, 2, 'deep_spawn', '混沌渡劫中期', '混沌渡劫进行中'), +(8, 3, 'deep_spawn', '混沌渡劫圆满', '混沌渡劫成功,准备飞升'), +(9, 1, 'deep_spawn', '旧日飞升初期', '飞升旧日界,成就大道'), +(9, 2, 'deep_spawn', '旧日飞升中期', '旧日界修行'), +(9, 3, 'deep_spawn', '旧日飞升圆满', '大道圆满,超脱轮回') +ON CONFLICT (realm_tier, minor_realm, race_id) DO UPDATE SET + name = EXCLUDED.name, + description = EXCLUDED.description; + +-- 8. 更新world_layers为5层世界 +DELETE FROM world_layers; + +INSERT INTO world_layers (tier, name, display_layer, realm_tier, is_pvp_enabled, cross_tier_rules) VALUES +(1, '凡界', 0, 1, false, '{"description":"种族完全隔离,炼气期"}'), +(2, '灵界', 1, 2, true, '{"description":"首次天启,跨种族相遇,筑基/金丹/元婴"}'), +(3, '道界', 2, 5, true, '{"description":"法则领悟,大道融合,化神/合体/大乘"}'), +(4, '圣界', 3, 8, true, '{"description":"顶级争夺,界域争霸,渡劫/飞升"}'), +(5, '神域', 4, 9, true, '{"description":"界域系统,域主竞争"}') +ON CONFLICT (tier) DO UPDATE SET + name = EXCLUDED.name, + display_layer = EXCLUDED.display_layer, + realm_tier = EXCLUDED.realm_tier, + is_pvp_enabled = EXCLUDED.is_pvp_enabled, + cross_tier_rules = EXCLUDED.cross_tier_rules; diff --git a/database/migrations/003_expand_manuals.up.sql b/database/migrations/003_expand_manuals.up.sql new file mode 100644 index 0000000..476d129 --- /dev/null +++ b/database/migrations/003_expand_manuals.up.sql @@ -0,0 +1,195 @@ +-- T003: 扩展功法系统 - 新增神通/秘术功法类型 +-- 对齐GDD-04 v1.12 新增决策✅22-✅26 + +-- 1. 扩展manuals表的category字段值(原有universal/profession/racial/unique) +-- 新增:divine(神通)、forbidden(秘术) + +-- 2. 创建功法类型配置表 +CREATE TABLE IF NOT EXISTS manual_types ( + id VARCHAR(32) PRIMARY KEY, + name VARCHAR(64) NOT NULL, + description TEXT, + max_equipped SMALLINT NOT NULL DEFAULT 0, -- 0=不限(自然约束) + acquisition_req JSONB NOT NULL DEFAULT '{}', -- 获取条件 + usage_cost JSONB NOT NULL DEFAULT '{}', -- 使用代价 + cooldown_config JSONB NOT NULL DEFAULT '{}', -- 冷却配置 + conflict_rules JSONB NOT NULL DEFAULT '[]', -- 冲突规则 + created_at TIMESTAMPTZ DEFAULT NOW() +); + +-- 3. 插入功法类型数据 +INSERT INTO manual_types (id, name, description, max_equipped, acquisition_req, usage_cost, cooldown_config, conflict_rules) VALUES +-- 基础功法类型 +('heart_method', '主修心法', '决定内力积累效率、内力上限、内力纯度基线', 0, '{}', '{}', '{}', '[]'), +('combat_skill', '战技功法', '修炼后解锁战斗招式(普攻强化/主动技/被动)', 0, '{}', '{}', '{}', '[]'), +('auxiliary', '辅助功法', '提供修炼/游历/纯化等增益', 0, '{}', '{}', '{}', '[]'), +('production', '生产联动功法', '与生活技能联动', 0, '{}', '{}', '{}', '[]'), +-- 新增功法类型(T002审阅) +('divine_power', '神通功法', '修炼到高境界后领悟的超凡能力,威力远超普通战技', 0, + '{"min_realm":4,"min_manual_layer":7,"require_epiphany":true}', + '{"energy_cost":"high","special_resource":"精血/寿元","battle_cooldown":"24-72h"}', + '{"battle_cooldown_hours":48}', + '[]'), +('forbidden_art', '秘术功法', '禁忌之术,代价高昂但威力极大', 0, + '{"min_realm":5,"require_special_bloodline":true,"require_special_item":true}', + '{"energy_cost":"extreme","karma_cost":"10-50业力","lifespan_cost":"数年寿元"}', + '{"battle_cooldown_hours":168}', + '[]'); + +-- 4. 扩展manuals表的category约束 +-- 注意:原有category字段是VARCHAR(32),无需修改,只需确保新值被接受 + +-- 5. 创建法宝对战系统表(GDD-03 附.A) +CREATE TABLE IF NOT EXISTS artifacts ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + character_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + item_id VARCHAR(64) NOT NULL REFERENCES items(id), + artifact_type VARCHAR(32) NOT NULL, -- weapon/armor/accessory + grade VARCHAR(16) NOT NULL, -- mortal/yellow/xuan/di/celestial/immortal + refinement_level SMALLINT NOT NULL DEFAULT 0, + spirit_level SMALLINT NOT NULL DEFAULT 0, -- 器灵等级 + spirit_name VARCHAR(64), + bound BOOLEAN NOT NULL DEFAULT false, + stats JSONB NOT NULL DEFAULT '{}', + skills JSONB NOT NULL DEFAULT '[]', + durability INT NOT NULL DEFAULT 100, + max_durability INT NOT NULL DEFAULT 100, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE INDEX idx_artifacts_character ON artifacts(character_id); +CREATE INDEX idx_artifacts_grade ON artifacts(grade, artifact_type); + +-- 6. 创建飞剑系统表(GDD-03 附.D) +CREATE TABLE IF NOT EXISTS flying_swords ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + character_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + item_id VARCHAR(64) NOT NULL REFERENCES items(id), + grade VARCHAR(16) NOT NULL, -- mortal/spirit/celestial/immortal/sacred + refinement_level SMALLINT NOT NULL DEFAULT 0, + sword_art_level SMALLINT NOT NULL DEFAULT 0, -- 御剑术等级 + stats JSONB NOT NULL DEFAULT '{}', + skills JSONB NOT NULL DEFAULT '[]', + bound BOOLEAN NOT NULL DEFAULT false, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE INDEX idx_flying_swords_character ON flying_swords(character_id); + +-- 7. 创建阵法系统表(GDD-03 附.C / GDD-27 二) +CREATE TABLE IF NOT EXISTS formations ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + character_id UUID REFERENCES characters(id) ON DELETE SET NULL, + guild_id UUID REFERENCES guilds(id) ON DELETE SET NULL, + zone_id UUID REFERENCES zones(id) ON DELETE SET NULL, + formation_type VARCHAR(32) NOT NULL, -- attack/defense/control/encapsulate/support/guild_defense + name VARCHAR(128) NOT NULL, + grade VARCHAR(16) NOT NULL, -- mortal/yellow/xuan/di/celestial/immortal + level SMALLINT NOT NULL DEFAULT 1, + materials JSONB NOT NULL DEFAULT '[]', + stats JSONB NOT NULL DEFAULT '{}', + duration_ticks INT NOT NULL DEFAULT 0, -- 0=永久 + maintenance_cost NUMERIC(20,4) NOT NULL DEFAULT 0, + is_active BOOLEAN NOT NULL DEFAULT false, + created_at TIMESTAMPTZ DEFAULT NOW(), + expires_at TIMESTAMPTZ +); + +CREATE INDEX idx_formations_character ON formations(character_id); +CREATE INDEX idx_formations_guild ON formations(guild_id); +CREATE INDEX idx_formations_zone ON formations(zone_id); + +-- 8. 创建符箓系统表(GDD-03 附.E) +CREATE TABLE IF NOT EXISTS talismans ( + id VARCHAR(64) PRIMARY KEY, + name VARCHAR(128) NOT NULL, + talisman_type VARCHAR(32) NOT NULL, -- attack/defense/auxiliary/control/special + grade VARCHAR(16) NOT NULL, -- mortal/yellow/xuan/di/celestial/immortal + effect_data JSONB NOT NULL DEFAULT '{}', + crafting_recipe JSONB NOT NULL DEFAULT '{}', + usage_limit SMALLINT NOT NULL DEFAULT 1, -- 每场战斗使用次数 + cooldown_ticks INT NOT NULL DEFAULT 0, + created_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE TABLE IF NOT EXISTS character_talismans ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + character_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + talisman_id VARCHAR(64) NOT NULL REFERENCES talismans(id), + quantity INT NOT NULL DEFAULT 1, + created_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE INDEX idx_character_talismans_character ON character_talismans(character_id); + +-- 9. 创建法宝套装系统表(GDD-05 4.9) +CREATE TABLE IF NOT EXISTS artifact_sets ( + id VARCHAR(64) PRIMARY KEY, + name VARCHAR(128) NOT NULL, + description TEXT, + piece_count SMALLINT NOT NULL DEFAULT 6, + set_bonus_2 JSONB NOT NULL DEFAULT '{}', + set_bonus_4 JSONB NOT NULL DEFAULT '{}', + set_bonus_6 JSONB NOT NULL DEFAULT '{}', + grade VARCHAR(16) NOT NULL, + created_at TIMESTAMPTZ DEFAULT NOW() +); + +-- 10. 扩展energy_purity和karma系统(GDD-04/GDD-02) +-- 在characters表新增字段(通过ALTER TABLE) +ALTER TABLE characters ADD COLUMN IF NOT EXISTS karma_accrued INT NOT NULL DEFAULT 0; +ALTER TABLE characters ADD COLUMN IF NOT EXISTS energy_purity NUMERIC(5,4) NOT NULL DEFAULT 1.0; +ALTER TABLE characters ADD COLUMN IF NOT EXISTS dantox_level INT NOT NULL DEFAULT 0; +ALTER TABLE characters ADD COLUMN IF NOT EXISTS lifespan_current INT NOT NULL DEFAULT 1000; +ALTER TABLE characters ADD COLUMN IF NOT EXISTS lifespan_max INT NOT NULL DEFAULT 1000; + +-- 11. 创建修炼瓶颈记录表(GDD-04 8.1.4) +CREATE TABLE IF NOT EXISTS cultivation_bottlenecks ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + character_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + manual_id VARCHAR(64) NOT NULL, + bottleneck_layer SMALLINT NOT NULL, + is_breakthrough BOOLEAN NOT NULL DEFAULT false, + breakthrough_method VARCHAR(32), -- pill/event/mentor/meditation/epiphany + created_at TIMESTAMPTZ DEFAULT NOW(), + breakthrough_at TIMESTAMPTZ +); + +CREATE INDEX idx_cultivation_bottlenecks_character ON cultivation_bottlenecks(character_id, is_breakthrough); + +-- 12. 创建走火入魔记录表(GDD-04 8.1.5) +CREATE TABLE IF NOT EXISTS qi_deviation_records ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + character_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + severity VARCHAR(16) NOT NULL, -- mild/moderate/severe/extreme + cause VARCHAR(32) NOT NULL, -- incompatible_manual/high_dantox/low_sanity/long_cultivation/bottleneck_fail + stat_penalty JSONB NOT NULL DEFAULT '{}', + duration_hours INT NOT NULL DEFAULT 4, + recovery_method VARCHAR(32), + created_at TIMESTAMPTZ DEFAULT NOW(), + recovered_at TIMESTAMPTZ +); + +CREATE INDEX idx_qi_deviation_character ON qi_deviation_records(character_id, severity); + +-- 13. 创建闭关修炼记录表(GDD-04 8.1.6) +CREATE TABLE IF NOT EXISTS closed_door_sessions ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + character_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + session_type VARCHAR(16) NOT NULL, -- short/medium/long + location_id UUID, -- 洞府/宗门闭关室/福地 + duration_hours INT NOT NULL, + cost_spirit_stones NUMERIC(20,4) NOT NULL DEFAULT 0, + proficiency_bonus NUMERIC(5,4) NOT NULL DEFAULT 0, + epiphany_bonus NUMERIC(5,4) NOT NULL DEFAULT 0, + bottleneck_bonus NUMERIC(5,4) NOT NULL DEFAULT 0, + status VARCHAR(16) NOT NULL DEFAULT 'active', -- active/completed/interrupted + special_event JSONB, + started_at TIMESTAMPTZ DEFAULT NOW(), + ends_at TIMESTAMPTZ NOT NULL, + completed_at TIMESTAMPTZ +); + +CREATE INDEX idx_closed_door_character ON closed_door_sessions(character_id, status); diff --git a/database/migrations/004_expand_karma_system.up.sql b/database/migrations/004_expand_karma_system.up.sql new file mode 100644 index 0000000..62bd81b --- /dev/null +++ b/database/migrations/004_expand_karma_system.up.sql @@ -0,0 +1,123 @@ +-- T004: 扩展天道系统 - 因果值/功德值/业力值系统 +-- 对齐GDD-02 13.5.5 因果系统 + T003审阅报告 + +-- 1. 创建因果系统表 +CREATE TABLE IF NOT EXISTS karma_records ( + id BIGSERIAL PRIMARY KEY, + character_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + karma_type VARCHAR(16) NOT NULL, -- good_evil/bonus/penalty + karma_value INT NOT NULL, -- 正数=善因,负数=恶因 + reason_code VARCHAR(64) NOT NULL, + related_id UUID, -- 关联的事件/战斗/任务ID + world_tier SMALLINT NOT NULL, + created_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE INDEX idx_karma_character ON karma_records(character_id, created_at); +CREATE INDEX idx_karma_type ON karma_records(karma_type, created_at); +COMMENT ON TABLE karma_records IS '因果记录表,记录玩家行为的因果关系'; + +-- 2. 创建因果轮回事件表 +CREATE TABLE IF NOT EXISTS karma_events ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + character_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + event_type VARCHAR(32) NOT NULL, -- good_tribute/bad_retribution + trigger_value INT NOT NULL, -- 触发时的因果值 + event_data JSONB NOT NULL DEFAULT '{}', + status VARCHAR(16) NOT NULL DEFAULT 'pending', -- pending/completed/failed + created_at TIMESTAMPTZ DEFAULT NOW(), + completed_at TIMESTAMPTZ +); + +CREATE INDEX idx_karma_events_character ON karma_events(character_id, status); + +-- 3. 扩展characters表字段(已在003中添加部分,这里补充) +-- 因果值字段(GDD-02 13.5.5) +ALTER TABLE characters ADD COLUMN IF NOT EXISTS karma_good INT NOT NULL DEFAULT 0; -- 善因积累 +ALTER TABLE characters ADD COLUMN IF NOT EXISTS karma_evil INT NOT NULL DEFAULT 0; -- 恶因积累 +ALTER TABLE characters ADD COLUMN IF NOT EXISTS karma_balance NUMERIC(10,2) NOT NULL DEFAULT 0; -- 因果平衡值 + +-- 4. 创建功德消耗记录表 +CREATE TABLE IF NOT EXISTS karma_expenditure_records ( + id BIGSERIAL PRIMARY KEY, + character_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + expenditure_type VARCHAR(32) NOT NULL, -- offset_sin/protect/buff/reward + amount INT NOT NULL, + related_id UUID, + created_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE INDEX idx_karma_expend_character ON karma_expenditure_records(character_id, created_at); + +-- 5. 创建功德护体效果表 +CREATE TABLE IF NOT EXISTS karma_shields ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + character_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + shield_type VARCHAR(32) NOT NULL, -- life_save/breakthrough_buff/luck_boost + trigger_condition JSONB NOT NULL DEFAULT '{}', + effect_data JSONB NOT NULL DEFAULT '{}', + is_active BOOLEAN NOT NULL DEFAULT true, + uses_remaining SMALLINT NOT NULL DEFAULT 1, + created_at TIMESTAMPTZ DEFAULT NOW(), + expires_at TIMESTAMPTZ +); + +CREATE INDEX idx_karma_shields_character ON karma_shields(character_id, is_active); + +-- 6. 创建功德馈赠事件表 +CREATE TABLE IF NOT EXISTS karma_gifts ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + character_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + gift_type VARCHAR(32) NOT NULL, -- fortune_favor/rare_opportunity/special_event + gift_data JSONB NOT NULL DEFAULT '{}', + is_claimed BOOLEAN NOT NULL DEFAULT false, + created_at TIMESTAMPTZ DEFAULT NOW(), + expires_at TIMESTAMPTZ +); + +CREATE INDEX idx_karma_gifts_character ON karma_gifts(character_id, is_claimed); + +-- 7. 创建业力累积记录表(GDD-04 秘术系统) +CREATE TABLE IF NOT EXISTS sin_accumulation ( + id BIGSERIAL PRIMARY KEY, + character_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE, + source_type VARCHAR(32) NOT NULL, -- forbidden_art/killing/betrayal/special_event + sin_amount INT NOT NULL, + reason_code VARCHAR(64) NOT NULL, + related_id UUID, + created_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE INDEX idx_sin_accumulation_character ON sin_accumulation(character_id, created_at); + +-- 8. 插入因果轮回事件配置 +INSERT INTO manual_types (id, name, description, max_equipped, acquisition_req, usage_cost, cooldown_config, conflict_rules) VALUES +('karma_event_good', '善因轮回事件', '因果值达到极端值时触发的善报事件', 0, + '{"min_karma_good":1000}', + '{"type":"tribute"}', + '{"min_interval_hours":168}', + '[]'), +('karma_event_evil', '恶因轮回事件', '因果值达到极端值时触发的恶报事件', 0, + '{"min_karma_evil":-1000}', + '{"type":"retribution"}', + '{"min_interval_hours":168}', + '[]') +ON CONFLICT (id) DO NOTHING; + +-- 9. 创建天道馈赠触发条件配置表 +CREATE TABLE IF NOT EXISTS karma_gift_conditions ( + id SERIAL PRIMARY KEY, + condition_type VARCHAR(32) NOT NULL, + threshold_value INT NOT NULL, + gift_type VARCHAR(32) NOT NULL, + gift_data JSONB NOT NULL DEFAULT '{}', + probability NUMERIC(5,4) NOT NULL DEFAULT 1.0, + cooldown_hours INT NOT NULL DEFAULT 168, + created_at TIMESTAMPTZ DEFAULT NOW() +); + +INSERT INTO karma_gift_conditions (condition_type, threshold_value, gift_type, gift_data, probability, cooldown_hours) VALUES +('karma_good', 100, 'breakthrough_buff', '{"success_rate_bonus":0.05,"description":"天道庇护:境界突破成功率+5%"}', 1.0, 720), +('karma_good', 500, 'luck_boost', '{"fortune_trigger_rate":0.10,"description":"天命相助:游历机缘触发概率+10%"}', 1.0, 720), +('karma_good', 1000, 'appearance_buff', '{"appearance":"功德身","heavenly_tribulation_reduce":1,"description":"功德圆满:获得功德身外观;渡劫时减少1次天劫"}', 1.0, 720), +('karma_good', 2000, 'rare_opportunity', '{"rare_event_chance":0.05,"description":"天道认可:极小概率获得天道馈赠机缘"}', 0.05, 720); diff --git a/deploy/docs/README.md b/deploy/docs/README.md new file mode 100644 index 0000000..086b78d --- /dev/null +++ b/deploy/docs/README.md @@ -0,0 +1,43 @@ +# 文档站部署 + +这套配置用于将 MkDocs 文档站部署到 `106.54.23.149`,并通过 `docs.xuqinmin.com` 访问。 + +## 目录约定 + +| 位置 | 用途 | +|------|------| +| `/var/www/docs.xuqinmin.com/site` | 文档站静态文件 | +| `/var/www/docs.xuqinmin.com/webroot` | ACME 校验目录 | +| `/etc/nginx/sites-available/docs.xuqinmin.com.conf` | Nginx 站点配置 | + +## 首次部署 + +1. 在服务器安装 `nginx`、`rsync`、`acme.sh`。 +2. 将仓库中的 `nginx-docs.conf` 放到 `/etc/nginx/sites-available/docs.xuqinmin.com.conf`。 +3. 创建目录: + +```bash +sudo mkdir -p /var/www/docs.xuqinmin.com/site /var/www/docs.xuqinmin.com/webroot +``` + +4. 启用 Nginx 站点并检查配置。 +5. 使用 `acme.sh` 的 webroot 模式为 `docs.xuqinmin.com` 申请证书,并安装到 `/opt/xuqm/acme/docs.xuqinmin.com_ecc/`。 +6. 将 `certbot-renew-hook.sh` 作为重载 Nginx 的通用 hook 使用,或者在 `acme.sh` 的 `--reloadcmd` 中直接调用 `systemctl reload nginx`。 + +## 自动更新 + +推荐在 `106.54.23.149` 上安装一个自动同步任务,执行入口建议使用仓库中的 `scripts/sync-docs-site.sh`。 + +该任务检测到 `main` 分支更新后会: + +1. 检出仓库。 +2. 安装 `mkdocs-material`。 +3. 构建站点。 +4. 同步到 `/var/www/docs.xuqinmin.com/site`。 + +## 本地预览 + +```bash +make docs-build +make docs-serve +``` diff --git a/deploy/docs/certbot-renew-hook.sh b/deploy/docs/certbot-renew-hook.sh new file mode 100644 index 0000000..d647392 --- /dev/null +++ b/deploy/docs/certbot-renew-hook.sh @@ -0,0 +1,6 @@ +#!/bin/sh +# 证书更新后执行 nginx 重载 + +set -eu + +systemctl reload nginx diff --git a/docker/nacos/Dockerfile b/docker/nacos/Dockerfile new file mode 100644 index 0000000..b54ca9f --- /dev/null +++ b/docker/nacos/Dockerfile @@ -0,0 +1,15 @@ +# 《洪荒大陆》Nacos 配置初始化镜像 +# 一次性容器:等待 Nacos 就绪 -> 创建 namespace -> 导入 configs/nacos/*.yaml + +FROM swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/curlimages/curl:latest + +LABEL description="Honghuang Nacos config importer" + +WORKDIR /app + +COPY docker/nacos/import-configs.sh /app/import-configs.sh +RUN chmod +x /app/import-configs.sh + +VOLUME ["/configs"] + +ENTRYPOINT ["/app/import-configs.sh"] diff --git a/docker/nacos/import-configs.sh b/docker/nacos/import-configs.sh new file mode 100644 index 0000000..f91114b --- /dev/null +++ b/docker/nacos/import-configs.sh @@ -0,0 +1,50 @@ +#!/bin/sh +# 将 configs/nacos/*.yaml 导入 Nacos(standalone 模式) +# 环境变量: +# NACOS_SERVER 默认 honghuang-nacos:8848 +# NACOS_NAMESPACE 默认 honghuang(会作为 namespace id 创建) + +set -e + +SERVER="${NACOS_SERVER:-honghuang-nacos:8848}" +NAMESPACE="${NACOS_NAMESPACE:-honghuang}" +BASE_URL="http://${SERVER}/nacos/v1/cs/configs" +NS_URL="http://${SERVER}/nacos/v1/console/namespaces" + +echo "[nacos-init] Waiting for Nacos at ${SERVER}..." +for i in $(seq 1 60); do + if curl -fsS "http://${SERVER}/nacos/v1/console/health/readiness" >/dev/null 2>&1; then + echo "[nacos-init] Nacos is ready." + break + fi + if [ "$i" -eq 60 ]; then + echo "[nacos-init] ERROR: Nacos did not become ready in time." >&2 + exit 1 + fi + sleep 2 +done + +# 创建 namespace(已存在时忽略错误) +echo "[nacos-init] Ensuring namespace '${NAMESPACE}' exists..." +curl -fsS -X POST "${NS_URL}?namespaceName=${NAMESPACE}&customNamespaceId=${NAMESPACE}" >/dev/null 2>&1 || true + +# 构造 tenant 参数:public/空表示默认空间,否则使用指定 namespace id +TENANT_ARG="" +if [ -n "${NAMESPACE}" ] && [ "${NAMESPACE}" != "public" ]; then + TENANT_ARG="--data-urlencode tenant=${NAMESPACE}" +fi + +echo "[nacos-init] Importing configs into namespace '${NAMESPACE}'..." +for f in /configs/*.yaml; do + [ -e "$f" ] || continue + DATA_ID="$(basename "$f")" + echo "[nacos-init] Publishing ${DATA_ID} ..." + curl -fsS -X POST "${BASE_URL}" \ + --data-urlencode "dataId=${DATA_ID}" \ + --data-urlencode "group=DEFAULT_GROUP" \ + ${TENANT_ARG} \ + --data-urlencode "content@${f}" >/dev/null + echo "[nacos-init] ${DATA_ID} imported." +done + +echo "[nacos-init] All Nacos configs imported successfully." diff --git a/docker/nakama/Dockerfile b/docker/nakama/Dockerfile new file mode 100644 index 0000000..221eed0 --- /dev/null +++ b/docker/nakama/Dockerfile @@ -0,0 +1,36 @@ +# 《洪荒大陆》Nakama 3.x 运行时镜像 +# - 使用 heroiclabs/nakama-pluginbuilder 编译 Go 插件 +# - 将插件与配置文件拷贝到 heroiclabs/nakama 镜像 + +# ----------------------------------------------------------------------------- +# 阶段 1:编译 Go 插件 +# ----------------------------------------------------------------------------- +FROM swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/heroiclabs/nakama-pluginbuilder:3.24.2 AS builder + +ENV GO111MODULE=on +ENV CGO_ENABLED=1 + +WORKDIR /backend + +# 项目 go.mod 使用 go 1.25 占位,builder 当前为 Go 1.23.x,降级 directive 以兼容本地构建 +COPY server/go.mod server/go.sum ./ +RUN sed -i 's/^go 1\.25/go 1.23/' go.mod && go mod download + +# 拷贝服务端全部源码并编译为共享对象 +COPY server/ ./ +RUN go build --trimpath --buildmode=plugin -o honghuang-server.so . + +# ----------------------------------------------------------------------------- +# 阶段 2:Nakama 运行时 +# ----------------------------------------------------------------------------- +FROM swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/heroiclabs/nakama:3.24.2 + +LABEL description="Honghuang Nakama 3.24.2 with Go plugin" + +# 加载洪荒大陆 Go 插件 +COPY --from=builder /backend/honghuang-server.so /nakama/data/modules/ + +# 加载 Nakama 配置文件 +COPY docker/nakama/config.yml /nakama/data/config.yml + +EXPOSE 7349 7350 7351 diff --git a/docker/nakama/config.yml b/docker/nakama/config.yml new file mode 100644 index 0000000..5c8c8c0 --- /dev/null +++ b/docker/nakama/config.yml @@ -0,0 +1,47 @@ +# 《洪荒大陆》Nakama 3.x 本地开发配置 +# 详见:https://heroiclabs.com/docs/nakama/getting-started/configuration/ + +name: honghuang-nakama + +data_dir: "./data/" + +logger: + stdout: true + level: "debug" + +database: + address: + - "postgres:postgres@postgres:5432/nakama" + conn_max_lifetime_ms: 0 + max_open_conns: 0 + max_idle_conns: 100 + +runtime: + # 插件扫描目录 + path: "/nakama/data/modules" + http_key: "defaulthttpkey" + # 透传给 Go 插件的环境变量 + env: + - "DATABASE_URL=postgres://postgres:postgres@postgres:5432/honghuang?sslmode=disable" + - "NACOS_SERVER=honghuang-nacos" + - "NACOS_NAMESPACE=honghuang" + +socket: + server_key: "defaultkey" + port: 7350 + max_message_size_bytes: 4096 + read_timeout_ms: 10000 + write_timeout_ms: 10000 + idle_timeout_ms: 60000 + outgoing_queue_size: 16 + +session: + encryption_key: "defaultencryptionkey" + token_expiry_sec: 7200 + refresh_encryption_key: "defaultrefreshencryptionkey" + refresh_token_expiry_sec: 3600 + +console: + port: 7351 + username: "admin" + password: "password" diff --git a/docker/postgres/Dockerfile b/docker/postgres/Dockerfile new file mode 100644 index 0000000..92a382a --- /dev/null +++ b/docker/postgres/Dockerfile @@ -0,0 +1,20 @@ +# 《洪荒大陆》本地开发 PostgreSQL 16 镜像 +# 基于官方 PostgreSQL 16,自动创建 honghuang 库并执行迁移/seed + +FROM swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/library/postgres:16-alpine + +LABEL description="Honghuang local dev PostgreSQL 16 with auto migration" + +# 将游戏迁移脚本复制到镜像内(不作为 docker-entrypoint-initdb.d 直接执行, +# 由 init-honghuang.sh 控制目标数据库) +COPY database/migrations /migrations + +# 复制本地开发脚本,供初始化阶段调用(如 scripts/seed.sh) +COPY scripts /scripts +RUN chmod +x /scripts/*.sh + +# 初始化脚本:创建 honghuang 库 -> 执行 up.sql -> 执行 scripts/seed.sh +COPY docker/postgres/init-honghuang.sh /docker-entrypoint-initdb.d/zz-init-honghuang.sh +RUN chmod +x /docker-entrypoint-initdb.d/zz-init-honghuang.sh + +EXPOSE 5432 diff --git a/docker/postgres/init-honghuang.sh b/docker/postgres/init-honghuang.sh new file mode 100644 index 0000000..358d732 --- /dev/null +++ b/docker/postgres/init-honghuang.sh @@ -0,0 +1,34 @@ +#!/bin/sh +# PostgreSQL 容器首次启动时执行: +# 1. 创建游戏业务库 HONGHUANG_DB(默认 honghuang) +# 2. 在该库执行 database/migrations/001_init_schema.up.sql(含参考数据 seed) +set -e + +DB_NAME="${HONGHUANG_DB:-honghuang}" +UP_SQL="/migrations/001_init_schema.up.sql" + +echo "[postgres-init] Creating database '${DB_NAME}' if not exists..." +psql -v ON_ERROR_STOP=1 -U "${POSTGRES_USER}" -d "${POSTGRES_DB}" <<-EOSQL + SELECT 'CREATE DATABASE ${DB_NAME}' + WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = '${DB_NAME}')\gexec +EOSQL + +if [ -f "${UP_SQL}" ]; then + echo "[postgres-init] Running ${UP_SQL} on database '${DB_NAME}'..." + psql -v ON_ERROR_STOP=1 -U "${POSTGRES_USER}" -d "${DB_NAME}" -f "${UP_SQL}" + echo "[postgres-init] Migration and seed completed." +else + echo "[postgres-init] WARNING: ${UP_SQL} not found, skipping game schema init." +fi + +# 执行开发测试数据种子脚本(scripts/seed.sh) +SEED_SCRIPT="/scripts/seed.sh" +if [ -f "${SEED_SCRIPT}" ] && [ -x "${SEED_SCRIPT}" ]; then + echo "[postgres-init] Running ${SEED_SCRIPT} on database '${DB_NAME}'..." + export DATABASE_URL="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:5432/${DB_NAME}?sslmode=disable" + export DB_WAIT_TIMEOUT=60 + bash "${SEED_SCRIPT}" + echo "[postgres-init] Seed script completed." +else + echo "[postgres-init] WARNING: ${SEED_SCRIPT} not found or not executable, skipping seed." +fi diff --git a/server/Makefile b/server/Makefile new file mode 100644 index 0000000..2854e37 --- /dev/null +++ b/server/Makefile @@ -0,0 +1,22 @@ +.PHONY: build run test lint clean + +BINARY_NAME=honghuang-server +GO=go +GOLANGCI_LINT=golangci-lint + +# Nakama Go 模块需要以 plugin 模式编译,输出 .so 供 Nakama 加载。 +build: + $(GO) build -buildmode=plugin -o $(BINARY_NAME).so . + +run: build + @echo "Nakama module built at $(BINARY_NAME).so" + @echo "Configure Nakama runtime -> path to load this shared object." + +test: + $(GO) test ./... + +lint: + $(GOLANGCI_LINT) run ./... + +clean: + rm -f $(BINARY_NAME).so diff --git a/server/go.mod b/server/go.mod new file mode 100644 index 0000000..ad9dd42 --- /dev/null +++ b/server/go.mod @@ -0,0 +1,74 @@ +module github.com/honghuang-game/server + +go 1.25 + +require ( + github.com/heroiclabs/nakama-common v1.34.0 + github.com/jackc/pgx/v5 v5.7.1 + github.com/nacos-group/nacos-sdk-go/v2 v2.2.9 + gopkg.in/yaml.v3 v3.0.1 +) + +require ( + github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6 // indirect + github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 // indirect + github.com/alibabacloud-go/darabonba-array v0.1.0 // indirect + github.com/alibabacloud-go/darabonba-encode-util v0.0.2 // indirect + github.com/alibabacloud-go/darabonba-map v0.0.2 // indirect + github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10 // indirect + github.com/alibabacloud-go/darabonba-signature-util v0.0.7 // indirect + github.com/alibabacloud-go/darabonba-string v1.0.2 // indirect + github.com/alibabacloud-go/debug v1.0.1 // indirect + github.com/alibabacloud-go/endpoint-util v1.1.0 // indirect + github.com/alibabacloud-go/kms-20160120/v3 v3.2.3 // indirect + github.com/alibabacloud-go/openapi-util v0.1.0 // indirect + github.com/alibabacloud-go/tea v1.2.2 // indirect + github.com/alibabacloud-go/tea-utils v1.4.4 // indirect + github.com/alibabacloud-go/tea-utils/v2 v2.0.7 // indirect + github.com/alibabacloud-go/tea-xml v1.1.3 // indirect + github.com/aliyun/alibaba-cloud-sdk-go v1.61.1800 // indirect + github.com/aliyun/alibabacloud-dkms-gcs-go-sdk v0.5.1 // indirect + github.com/aliyun/alibabacloud-dkms-transfer-go-sdk v0.1.8 // indirect + github.com/aliyun/aliyun-secretsmanager-client-go v1.1.5 // indirect + github.com/aliyun/credentials-go v1.4.3 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/buger/jsonparser v1.1.1 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/clbanning/mxj/v2 v2.5.5 // indirect + github.com/deckarep/golang-set v1.7.1 // indirect + github.com/golang/mock v1.6.0 // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect + github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/orcaman/concurrent-map v0.0.0-20210501183033-44dafcb38ecc // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/prometheus/client_golang v1.12.2 // indirect + github.com/prometheus/client_model v0.2.0 // indirect + github.com/prometheus/common v0.32.1 // indirect + github.com/prometheus/procfs v0.7.3 // indirect + github.com/rogpeppe/go-internal v1.15.0 // indirect + github.com/tjfoc/gmsm v1.4.1 // indirect + go.uber.org/atomic v1.7.0 // indirect + go.uber.org/multierr v1.6.0 // indirect + go.uber.org/zap v1.21.0 // indirect + golang.org/x/crypto v0.31.0 // indirect + golang.org/x/net v0.33.0 // indirect + golang.org/x/sync v0.10.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.1.0 // indirect + google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect + google.golang.org/grpc v1.56.3 // indirect + google.golang.org/protobuf v1.34.1 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect +) + +// Nakama 3.x Go runtime:RPC handler 签名使用 runtime 包提供的 Logger / NakamaModule 接口。 +// 如遇版本冲突,可尝试升级 nakama-common 到最新 patch 或降级到 v1.33.x。 diff --git a/server/go.sum b/server/go.sum new file mode 100644 index 0000000..40962cb --- /dev/null +++ b/server/go.sum @@ -0,0 +1,686 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6 h1:eIf+iGJxdU4U9ypaUfbtOWCsZSbTb8AUHvyPrxu6mAA= +github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6/go.mod h1:4EUIoxs/do24zMOGGqYVWgw0s9NtiylnJglOeEB5UJo= +github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc= +github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 h1:zE8vH9C7JiZLNJJQ5OwjU9mSi4T9ef9u3BURT6LCLC8= +github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5/go.mod h1:tWnyE9AjF8J8qqLk645oUmVUnFybApTQWklQmi5tY6g= +github.com/alibabacloud-go/darabonba-array v0.1.0 h1:vR8s7b1fWAQIjEjWnuF0JiKsCvclSRTfDzZHTYqfufY= +github.com/alibabacloud-go/darabonba-array v0.1.0/go.mod h1:BLKxr0brnggqOJPqT09DFJ8g3fsDshapUD3C3aOEFaI= +github.com/alibabacloud-go/darabonba-encode-util v0.0.2 h1:1uJGrbsGEVqWcWxrS9MyC2NG0Ax+GpOM5gtupki31XE= +github.com/alibabacloud-go/darabonba-encode-util v0.0.2/go.mod h1:JiW9higWHYXm7F4PKuMgEUETNZasrDM6vqVr/Can7H8= +github.com/alibabacloud-go/darabonba-map v0.0.2 h1:qvPnGB4+dJbJIxOOfawxzF3hzMnIpjmafa0qOTp6udc= +github.com/alibabacloud-go/darabonba-map v0.0.2/go.mod h1:28AJaX8FOE/ym8OUFWga+MtEzBunJwQGceGQlvaPGPc= +github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.9/go.mod h1:bb+Io8Sn2RuM3/Rpme6ll86jMyFSrD1bxeV/+v61KeU= +github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10 h1:GEYkMApgpKEVDn6z12DcH1EGYpDYRB8JxsazM4Rywak= +github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10/go.mod h1:26a14FGhZVELuz2cc2AolvW4RHmIO3/HRwsdHhaIPDE= +github.com/alibabacloud-go/darabonba-signature-util v0.0.7 h1:UzCnKvsjPFzApvODDNEYqBHMFt1w98wC7FOo0InLyxg= +github.com/alibabacloud-go/darabonba-signature-util v0.0.7/go.mod h1:oUzCYV2fcCH797xKdL6BDH8ADIHlzrtKVjeRtunBNTQ= +github.com/alibabacloud-go/darabonba-string v1.0.2 h1:E714wms5ibdzCqGeYJ9JCFywE5nDyvIXIIQbZVFkkqo= +github.com/alibabacloud-go/darabonba-string v1.0.2/go.mod h1:93cTfV3vuPhhEwGGpKKqhVW4jLe7tDpo3LUM0i0g6mA= +github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68/go.mod h1:6pb/Qy8c+lqua8cFpEy7g39NRRqOWc3rOwAy8m5Y2BY= +github.com/alibabacloud-go/debug v1.0.0/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc= +github.com/alibabacloud-go/debug v1.0.1 h1:MsW9SmUtbb1Fnt3ieC6NNZi6aEwrXfDksD4QA6GSbPg= +github.com/alibabacloud-go/debug v1.0.1/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc= +github.com/alibabacloud-go/endpoint-util v1.1.0 h1:r/4D3VSw888XGaeNpP994zDUaxdgTSHBbVfZlzf6b5Q= +github.com/alibabacloud-go/endpoint-util v1.1.0/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE= +github.com/alibabacloud-go/kms-20160120/v3 v3.2.3 h1:vamGcYQFwXVqR6RWcrVTTqlIXZVsYjaA7pZbx+Xw6zw= +github.com/alibabacloud-go/kms-20160120/v3 v3.2.3/go.mod h1:3rIyughsFDLie1ut9gQJXkWkMg/NfXBCk+OtXnPu3lw= +github.com/alibabacloud-go/openapi-util v0.1.0 h1:0z75cIULkDrdEhkLWgi9tnLe+KhAFE/r5Pb3312/eAY= +github.com/alibabacloud-go/openapi-util v0.1.0/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws= +github.com/alibabacloud-go/tea v1.1.0/go.mod h1:IkGyUSX4Ba1V+k4pCtJUc6jDpZLFph9QMy2VUPTwukg= +github.com/alibabacloud-go/tea v1.1.7/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= +github.com/alibabacloud-go/tea v1.1.8/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= +github.com/alibabacloud-go/tea v1.1.11/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= +github.com/alibabacloud-go/tea v1.1.17/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A= +github.com/alibabacloud-go/tea v1.1.20/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A= +github.com/alibabacloud-go/tea v1.2.1/go.mod h1:qbzof29bM/IFhLMtJPrgTGK3eauV5J2wSyEUo4OEmnA= +github.com/alibabacloud-go/tea v1.2.2 h1:aTsR6Rl3ANWPfqeQugPglfurloyBJY85eFy7Gc1+8oU= +github.com/alibabacloud-go/tea v1.2.2/go.mod h1:CF3vOzEMAG+bR4WOql8gc2G9H3EkH3ZLAQdpmpXMgwk= +github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE= +github.com/alibabacloud-go/tea-utils v1.4.4 h1:lxCDvNCdTo9FaXKKq45+4vGETQUKNOW/qKTcX9Sk53o= +github.com/alibabacloud-go/tea-utils v1.4.4/go.mod h1:KNcT0oXlZZxOXINnZBs6YvgOd5aYp9U67G+E3R8fcQw= +github.com/alibabacloud-go/tea-utils/v2 v2.0.3/go.mod h1:sj1PbjPodAVTqGTA3olprfeeqqmwD0A5OQz94o9EuXQ= +github.com/alibabacloud-go/tea-utils/v2 v2.0.5/go.mod h1:dL6vbUT35E4F4bFTHL845eUloqaerYBYPsdWR2/jhe4= +github.com/alibabacloud-go/tea-utils/v2 v2.0.6/go.mod h1:qxn986l+q33J5VkialKMqT/TTs3E+U9MJpd001iWQ9I= +github.com/alibabacloud-go/tea-utils/v2 v2.0.7 h1:WDx5qW3Xa5ZgJ1c8NfqJkF6w+AU5wB8835UdhPr6Ax0= +github.com/alibabacloud-go/tea-utils/v2 v2.0.7/go.mod h1:qxn986l+q33J5VkialKMqT/TTs3E+U9MJpd001iWQ9I= +github.com/alibabacloud-go/tea-xml v1.1.3 h1:7LYnm+JbOq2B+T/B0fHC4Ies4/FofC4zHzYtqw7dgt0= +github.com/alibabacloud-go/tea-xml v1.1.3/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8= +github.com/aliyun/alibaba-cloud-sdk-go v1.61.1800 h1:ie/8RxBOfKZWcrbYSJi2Z8uX8TcOlSMwPlEJh83OeOw= +github.com/aliyun/alibaba-cloud-sdk-go v1.61.1800/go.mod h1:RcDobYh8k5VP6TNybz9m++gL3ijVI5wueVr0EM10VsU= +github.com/aliyun/alibabacloud-dkms-gcs-go-sdk v0.5.1 h1:nJYyoFP+aqGKgPs9JeZgS1rWQ4NndNR0Zfhh161ZltU= +github.com/aliyun/alibabacloud-dkms-gcs-go-sdk v0.5.1/go.mod h1:WzGOmFFTlUzXM03CJnHWMQ85UN6QGpOXZocCjwkiyOg= +github.com/aliyun/alibabacloud-dkms-transfer-go-sdk v0.1.8 h1:QeUdR7JF7iNCvO/81EhxEr3wDwxk4YBoYZOq6E0AjHI= +github.com/aliyun/alibabacloud-dkms-transfer-go-sdk v0.1.8/go.mod h1:xP0KIZry6i7oGPF24vhAPr1Q8vLZRcMcxtft5xDKwCU= +github.com/aliyun/aliyun-secretsmanager-client-go v1.1.5 h1:8S0mtD101RDYa0LXwdoqgN0RxdMmmJYjq8g2mk7/lQ4= +github.com/aliyun/aliyun-secretsmanager-client-go v1.1.5/go.mod h1:M19fxYz3gpm0ETnoKweYyYtqrtnVtrpKFpwsghbw+cQ= +github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw= +github.com/aliyun/credentials-go v1.3.1/go.mod h1:8jKYhQuDawt8x2+fusqa1Y6mPxemTsBEN04dgcAcYz0= +github.com/aliyun/credentials-go v1.3.6/go.mod h1:1LxUuX7L5YrZUWzBrRyk0SwSdH4OmPrib8NVePL3fxM= +github.com/aliyun/credentials-go v1.3.10/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U= +github.com/aliyun/credentials-go v1.4.3 h1:N3iHyvHRMyOwY1+0qBLSf3hb5JFiOujVSVuEpgeGttY= +github.com/aliyun/credentials-go v1.4.3/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= +github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/clbanning/mxj/v2 v2.5.5 h1:oT81vUeEiQQ/DcHbzSytRngP6Ky9O+L+0Bw0zSJag9E= +github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ= +github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/heroiclabs/nakama-common v1.34.0 h1:7/F5v5yoCFBMTn5Aih/cqR/GW7hbEbup8blq5OmhzjM= +github.com/heroiclabs/nakama-common v1.34.0/go.mod h1:lPG64MVCs0/tEkh311Cd6oHX9NLx2vAPx7WW7QCJHQ0= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs= +github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nacos-group/nacos-sdk-go/v2 v2.2.9 h1:etzCMnB9EBeSKfaDIOe8zH4HO/8fycpc6s0AmXCrmAw= +github.com/nacos-group/nacos-sdk-go/v2 v2.2.9/go.mod h1:9FKXl6FqOiVmm72i8kADtbeK71egyG9y3uRDBg41tpQ= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/orcaman/concurrent-map v0.0.0-20210501183033-44dafcb38ecc h1:Ak86L+yDSOzKFa7WM5bf5itSOo1e3Xh8bm5YCMUXIjQ= +github.com/orcaman/concurrent-map v0.0.0-20210501183033-44dafcb38ecc/go.mod h1:Lu3tH6HLW3feq74c2GC+jIMS/K2CFcDWnWD9XkenwhI= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.2 h1:51L9cDoUHVrXx4zWYlcLQIZ+d+VXHgqnYKkIuq4g/34= +github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.15.0 h1:D0RCU5rMAp+SpgkiNdrjfJ+LX4J1M32V2NeCY7EJ6hc= +github.com/rogpeppe/go-internal v1.15.0/go.mod h1:DrUVZyrJU+txYW5/1kwtXQSMFio52ZOxX7yM1VHvnxs= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w= +github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho= +github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA= +golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= +google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc= +google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= +google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/server/honghuang-server.so b/server/honghuang-server.so new file mode 100644 index 0000000..1001a12 Binary files /dev/null and b/server/honghuang-server.so differ diff --git a/server/honghuang.so b/server/honghuang.so new file mode 100644 index 0000000..998a027 Binary files /dev/null and b/server/honghuang.so differ