• 如果您发现没有下载许可,请先验证邮箱再进行下载;金锭可通过每日签到或资源出售获取,目前没有其他渠道可获取。
  • 游客, 欢迎您来到九域资源社区,如果您是新人,请前往 论坛公告 板块查看新人引导教程 或者 点我打开
  • 已支持自助资源推荐投送,可在资源“更多选项”中使用金粒投放。
  • 已支持 API 上传资源版本更新,点击了解详情。
  • 已支持付费资源设置购买协议,可在“更多选项”中设置。
  • 全站已支持 Markdown 格式文本编辑器,可自由选择使用 BB 代码或 Markdown 格式。
资源图标

原创 GlobalMarket-宝可梦全球市场[服务端专用][1.12.2] 1.2.0

1.2.0(最新):能按「物品说明」和「宝可梦标记」禁止出售

这次加了什么

除了按"物品 ID"和"宝可梦种类"禁售,服务器现在还能规定:

  • 物品说明里写了某些字,就不许卖 —— 比如"绑定""不可交易"这类字样。 说明上颜色代码会被自动忽略(写成红字还是灰字都一样能认出来),大小写也不计较;
  • 宝可梦身上带了某个标记,就不许卖 —— 比如 Pixelmon 自带的"不可交易"标记 (untradeable)。标记大小写怎么写都认,不用担心写错大小写就失效。

两条都是可以写多条的名单,而且完全在服务端检查,客户端改不了、绕不过。

服主怎么开

配置里 blacklist 段多了三行:

代码:
blacklist {
    # 物品说明里出现这些字就不让卖
    # 直接写文字 = 任意一行"含有"就拦;以 = 开头 = "整行必须完全一样"
    S:item-lore <
        =灵魂绑定
        不可交易
     >

    # 宝可梦带这些标记就不让卖(大小写随意)
    S:pokemon-flags <
        untradeable
     >

    # 上面两条是否也管「寄送」(默认 true:卖不掉的东西也不能送人)
    B:restrict-gift=true
}
  • 两个名单默认是空的,也就是什么都不拦 —— 升级后行为和原来一模一样,想用哪个自己填;
  • 改完 /globalmarket reload 立刻生效,不用重启服务器;
  • 按物品 ID / 宝可梦种类禁售的老名单一直都管寄送,不受 restrict-gift 影响。

玩家会看到什么

被拦下时会明确告诉原因,例如:

该物品的说明中含有禁止交易的内容(不可交易),无法上架或寄送。

括号里就是命中的那条规则。有 globalmarket.bypass.blacklist 权限的管理员账号不受影响, 也不用另外开新权限。

三个要知道的点

  1. 说明(lore)不是安全机制:玩家用铁砧改名、用 NBT 编辑器就能自己加或去掉说明; 宝可梦的标记也能被有 /pokeedit 权限的人去掉。这两条规则拦的是"误卖 / 违规卖", 不能当绑定、防盗、防复制的手段用。
  2. 不管已经挂着的货:改了规则不会去动已经上架的旧商品(它们照旧在卖), 需要服主自己用 /globalmarket admin remove <挂单号> 处理。
  3. 只认标准位置:物品只看它的"说明",宝可梦只看身上的标记和自定义数据。 把这类信息存在别处的模组(很少见)识别不到。

升级步骤

和下面 1.1.0 一样:换 jar → 重启一次服务端。配置会自动补上三个新键, 默认值就是"不启用",所以什么都不用改。

更新日志

1.1.0 · 拍卖行 / 玩家寄送 / 分钟级时长

新增

  • 拍卖行([auction] 配置分区,auction.enabled 总开关):

    • 出价即冻结:出价时钱立即从账户扣走挂到拍卖上,被超越立刻退回, 中标时扣税付给卖家——到点结算不依赖中标者当时还有没有钱;
    • 同一人连续加价只扣差额;被超越者在线时收到聊天提示;
    • 到点自动结算(每 10 秒扫一批):有出价 → 发货给最高出价者、付款给卖家 (直接转账失败进邮箱);无人出价 → 流拍退回卖家邮箱;
    • 幂等与崩溃恢复:结算以 transactions 表唯一键 auction:<id>:pay 为幂等键, 按 stage 断点续做;服务端启动时自动续完卡在 SETTLING 的拍卖;
    • 三条双花防线:拍卖不能被 buy 买走(markReserved 限定 sale_type='FIXED')、 不会被GTS 的过期扫描捞走、有人出价后不能直接下架;
    • 界面:商品卡片显示当前价(青色)与剩余倒计时;底部「出价」打开出价界面 (当前价 / 出价次数 / 剩余时间 / 最高出价者 / 最近 3 条出价历史);
    • 上架拆成两套独立流程(各占一屏,不共用输入框): GTS 物品 / GTS 宝可梦(填单价)与 拍卖物品 / 拍卖宝可梦(只填起拍价), 每屏导航行三按钮:返回 / 换品类 / 换售卖方式,服务端关掉拍卖时不显示「拍卖」入口;
    • 拍卖时长是纯服务端配置:界面上是只读文本、命令不收时长参数、网络包不传时长, 玩家没有任何地方能改它;
    • 术语:原来的固定价售卖方式正式叫 GTS(数据库仍存 sale_type='FIXED'), 与「拍卖」并列;旧挂单全部自动归为 GTS,行为不变;
    • 筛选:浏览页新增「售卖方式」筛选(全部 / GTS / 拍卖);
    • 悬浮描述:拍卖显示当前价、出价次数、最高出价者,并新增占位符 {sale_type} {auction_current} {auction_count} {auction_leader} {auction_left} {auction_line} {auction_bid_line} {auction_leader_line} (GTS 挂单这些占位符都是空串,整行自动省略);
    • 命令:/globalmarket bid|auction|auctionpokemon;
    • 配置:auction.enabled、auction.duration(拍卖时长,玩家不可选)、 auction.min-increment、auction.min-increment-percent、auction.anti-snipe-enabled、 auction.anti-snipe-window-seconds、auction.anti-snipe-extend-seconds (反狙击默认关闭);协议版本 5 → 6,配置版本 6 → 7,数据库 schema 6 → 7。
  • 宝可梦属性本地名称:悬浮描述与查看面板里的种类 / 形态 / 性格 / 特性 / 球种 / 招式 / 体型 优先显示玩家客户端语言的名称(直接查 Pixelmon 自带语言表,如 皮卡丘 / 固执 / 静电 / 十万伏特 / 精灵球),该语言缺词条时回退内部名;玩家昵称永远最优先;

  • 货物税收显示:税收开启时,每个货物的悬浮描述在价格行下自动补一行 "税收 ¥50(税率 5%)"(按单价计算,与服务端实扣同一套整数算法,向下取整); 自定义模板可用新增占位符 {tax}(单价税额)、{tax_total}(剩余全量税额)、 {tax_rate}(税率文本)、{tax_line}(整行,税收关闭时整行自动省略); 税收关闭时握手包下发税率为 0,客户端据此整行省略;

  • 玩家间邮箱寄送:/globalmarket send <玩家> [数量] 把主手物品寄进对方的市场邮箱 (缺省寄出整组);/globalmarket sendpokemon <玩家> <队伍槽位0-5> 把队伍宝可梦送给对方。 收件人在市场邮箱领取(原因"好友寄送"),上线即有 Tab 补全(在线玩家名 / 槽位)。 与上架同一套保护:物品与宝可梦黑名单生效、队伍最后一只不能送出、战斗中不能寄送宝可梦、 全程写审计;寄件中途失败时物品/宝可梦原路退回,绝不弄丢;

  • 收件人离线也能寄:投递链路本来就只认 UUID + 名字,这次把命令层的"只认在线玩家" 换成"在线优先、离线回退到原版玩家档案(usercache)"。收件人在线会立刻收到聊天提示, 离线则静默投递,等他下次上线后在邮箱里领取。代价是只能寄给曾经进过服的玩家 (档案里有记录才有 UUID),从没进服过的陌生名字会明确提示找不到,而不是静默失败; ⚠ 这里有个坑:离线模式(online-mode=false)下原版档案会给任意未知名现场合成一个 离线 UUID,直接看 getGameProfileForUsername 的返回值永远查得到——打错一个字母也会 "寄送成功",物品就此躺在一个不会再上线的 UUID 名下。所以放行前会先用查询前的 usercache 快照判一次"是否真的认识这个名字",两种服务端模式下行为一致, 且被拒绝的未知名不会被写进档案;

  • 寄送界面:主界面底部导航新增「寄送」(物品 / 宝可梦 两个页签可互相切换)。 填收件人名字 → 从背包点一格(或从宝可梦列表选一只)→ 确认寄出; 物品数量留空或超量时按整组寄出;宝可梦列表 Party 与 PC 都会列出, 队伍里的最后一只不能送出(PC 里的不受限);寄送默认走二次确认。

界面

  • 底部导航从 5 个按钮扩到 6 个(浏览 / 我的在售 / 上架 / 历史 / 邮箱 / 寄送), 按钮宽度由 MarketTheme.navWidth 按面板宽度等分,仍然居中且不会顶出面板;
  • 悬浮描述模板新增 {icon_info} 占位符:物品原版描述(附魔、lore、耐久、宝可梦照片 自带资料等)以前固定渲染在模板内容的最前面,现在由模板决定位置——模板里单独占一行, 渲染时按原版内容展开成多行(各行的颜色代码与原版空行原样保留); 不写 {icon_info} 就不显示(此时也不会解析图标);模板渲染无内容时整行自动省略; 配了模板后描述里不再自动前置图标自带信息;
  • 删除 tooltip.show-icon-info 配置项:图标自带信息的显示现在完全由模板 {icon_info} 占位符控制(内置默认仍会自动显示)。旧配置文件里的该项会在升级时自动清理; 握手协议里该开关的位置保留为占位字节,新旧版本客户端与服务端混跑不会错位;
  • 购买物品可以输入数量了:购买确认界面新增数量输入框(1 到剩余数量), 实时显示总价(单价 × 数量);宝可梦挂单一次一只,不显示数量输入。 上架界面本来就是"单价 + 数量"形式,买家现在可以只买其中一部分;
  • 购买、下架、上架(物品/宝可梦) 都会先弹二次确认(服务端 market.confirm-actions=false 可关闭);
  • 确认弹窗按钮重新排版:宽度收进浅蓝色内容框、纵向对齐底部装饰带,不再压到贴图边框;
  • 邮箱与历史界面改成与主界面一致的图标卡片:每行左侧画货物图标(金币邮件画 $ 占位), 鼠标悬停显示详细描述(货物描述、类型、原因、金额、来源挂单、发放/成交时间、买家/卖家、 实付/实收/税金、交易状态等);
  • 搜索框占位文字改回原字号,不再顶出输入框;
  • 所有输入框不再铺底图:以前每个 GuiTextField 底下都铺一张 gts/controls/search_bar(按钮造型的灰底),又比文本框大一圈(宽 62 vs 54、高 16 vs 12), 于是输入框右下角总露出一截"按钮边"。现在一律只保留 GuiTextField 自带的黑底 + 灰边, 和主市场搜索框完全一致(上架物品 / 上架宝可梦 / 拍卖上架 / 购买确认 / 寄送 / 出价共 10 处); 输入框同时按原框位放大到与所在行等高(16~20px),不再是 12px 的小条;
  • 宝可梦上架页页脚不再重叠:以前"单价 / 起拍价"标签的位置是从输入框往左硬推的, 正好压在翻页的"下一页"按钮上(实机截图里"单"字叠在按钮右半边)。 现在四段按顺序从两端往中间排(翻页器 → 标签 → 输入框 → 确认按钮), 标签左边界取 MarketTheme.pagerEndX(),宽度由输入框位置反推,与语言/翻译长度无关; 为此翻页器宽度由 40 收窄到 34(贴图原生 32,视觉几乎无变化), 页脚腾出的空间让"起拍价"三个汉字也能按 2 倍完整绘制;
  • 筛选面板的性格改成"点选"而不是"手打":性格是 25 种固定枚举,以前要玩家把内部名 (Adamant)敲进文本框才筛得出来。现在面板里直接铺成 5×6 网格(第 1 格是"不限"), 显示的是玩家语言的性格名(固执 / Adamant,取自 Pixelmon 自己的语言表), 发出去的仍是内部名(服务端那条 pokemon_nature LIKE ? 比的就是 EnumNature.name()); 再点一次当前格 = 取消筛选。内部名清单在 NatureNames(javap 核对过枚举声明顺序), 离线自检会拿它去核对 Pixelmon 语言表里的 25 条 enum.nature.* 词条; 弹窗高度 192 → 258 并夹进"标题带以下、操作行以上",不会压到工具栏和底部导航;
  • 邮箱与历史改为每页 5 条的紧凑卡片(16px 图标 + 两行小字),界面高度明显缩小;
  • 页码框里的三位数页码改为自动缩小(用 drawFitCenteredScaled),不再压出边框。

修复

  • 筛选面板不再被商品图标穿透:物品图标是用 RenderItem 画的,它把模型摆到 z=100 上并写深度缓冲,后面所有 z=0 的二维绘制会被深度测试判掉——于是羊毛/石头这类 图标整个浮在"筛选"面板上面。修法是定死一条不变量:只有画物品时才临时开深度测试, 画完立刻关掉(MarketTheme.drawIcon),并且筛选面板在绘制前再显式关一次 (与原版 GuiContainer.drawScreen / GuiScreen.drawHoveringText 的做法一致);
  • 悬浮描述严格遵循服务端模板:tooltip.item-lines / tooltip.pokemon-lines 配了模板后,模组不再在末尾追加"右键快速购买 1 个"提示行、不再预加名称行、 也不再多渲染等级/性格/特性等宝可梦资料行——模板没写的内容一律不出现; 内置默认(模板留空)不受影响。同时修掉了默认描述里快速购买提示重复出现两次的问题;
  • 已过期挂单不再"赖"在市场上:市场列表(含「我的在售」)会实时剔除过期商品, 不再出现"剩余 0s 的货要等几十秒才消失";过期扫描每轮从 5 条提到 64 条并循环清空积压, 默认扫描间隔 60 秒 → 15 秒(listing.expire-check-seconds,旧配置文件需手动改)。
  • 管理员强制下架拍卖时,出价者冻结的钱不再丢失(资金丢失,P1): /globalmarket admin remove <id> 取消一场已有出价的拍卖时,从前只把挂单置为 CANCELLED 并把货退给卖家,完全不碰 bids、也不退款——那条 LEADING 托管凭据 就永久挂在一场已经结束的拍卖上。结算扫描(listExpiredAuctionIds)只挑 ACTIVE, 从此再没有任何后台任务会看到它,出价者被冻结的钱谁也退不了(实测一轮 60 人压测中 丢过 60000)。现在 forceCancel 把「状态迁移 + 把 LEADING 置为 REFUNDED」 放进同一个写事务(要么都成、要么整体回滚,绝不留孤儿凭据),提交后再把退款 打给出价者(离线/经济不可用自动转市场邮件),最后才把货退给卖家。 管理员取消拍卖的结局从此与流拍一致:卖家白忙一场,但没有任何人的钱被吞掉。 审计记录里同时留下 refundBidder=<名字>:<金额>,崩溃后也能查到该退谁多少钱。
  • globalmarket.bypass.blacklist 权限真正生效:该权限在工作组内早已文档化, 但代码里从不检查——四处黑名单校验(上架物品 / 上架宝可梦 / 寄送物品 / 寄送宝可梦) 都没有绕过入口。现在持有该权限的玩家(管理员、活动账号等)可以自由上架与寄送 黑名单内的物品与宝可梦,与 globalmarket.bypass.limit 的写法保持一致。

新增

  • 上架成功通知:上架后给卖家发一条可点击的聊天消息,点击直接打开市场界面; 正文/提示/悬停/点击命令与开关全部可在配置的 [notify] 段自定义, 模板支持 {name} {quantity} {price} {total} {currency} {id} {type} 等占位符 与 & 颜色代码;留空则用内置文案(跟随玩家客户端语言)。详见 README「上架通知自定义」。

配置

  • 上架过期时间与拍卖时长支持分钟:listing.expire-hours → listing.expire、 auction.duration-hours → auction.duration,值改成一套"时长写法": 30m(分钟)/ 2h(小时)/ 1h30m / 1d(天),可任意组合, 纯数字按分钟算(90 = 90 分钟),0 表示关闭(对 expire 即永不过期)。 从此可以配出"挂单 30 分钟自动下架"和"30 分钟速拍"这类比小时更短的策略。
    • 旧配置不用手动改:原来的小时整数会在启动时自动换算(6 → 6h) 写进新键,设过的值不会被丢弃,旧键随后被自动清理(日志里会列出)。 换算只在启动时做一次 —— /globalmarket reload 不会重跑(Forge 的配置对象会保留 内存里已有的键,热重载时新键已存在,因此以新键为准);升级后重启一次服务端即可;
    • 写错不会让模组起不来:解析不出来就打一条 WARN 并退回默认值 (expire → 0,auction.duration → 24h);超出各自范围则夹到边界 (1 分钟 ~ 10 年 / 1 分钟 ~ 7 天),"写错"与"写太大"是两种不同的处理,不会混淆;
    • 界面与命令的时长文案自动选单位("2 小时" / "30 分钟" / "1 小时 30 分", 英文 "2 h" / "30 min" / "1 h 30 min"),跟随玩家语言,不再硬编码"小时";
    • 协议版本 6 → 7(握手包里的拍卖时长单位由小时改为分钟,字节布局不变)、 配置版本 7 → 8(新增时长解析器 TimeUtil.parseDurationMinutes, 自检覆盖组合写法、大小写、非法输入、上下限等 20 条边界)。
  • 网络限流间隔可配置([network] 段,/globalmarket reload 热生效): action-cooldown-millis(默认 300,两次上架/购买/下架/领取的最小间隔)与 heavy-read-cooldown-millis(默认 1000,「列出我的宝可梦」等重读取的最小间隔); 读取与操作分开计时,上架后立刻刷新列表不再被误判为"操作过于频繁", 读请求被限流时也不再向聊天栏刷提示;
  • 悬浮描述模板新增宝可梦属性占位符:六项个体({iv_hp}…{iv_spe})、六项努力({ev_hp}…{ev_spe})、 六项实时能力值({stat_hp}…{stat_spe})、{ev_total}、{pokerus}、{egg}; 完整清单见 README「货物悬浮描述自定义」。

内部

  • 清理死代码 94 处(纯内部整理,行为零变化):66 个零引用成员 (方法/字段/常量,如 MarketTheme 里 7 个没人调的绘制辅助、ExpiryTask 里 过期改走邮箱后遗留的"直发背包"分支、TimeUtil.dayKey 等)、12 条未使用 import、 1 个未使用局部变量、14 条无人引用的语言键、13 张不再被引用的界面贴图; 语言键清理后中英键集合完全一致(当前各 328 条)。
  • 判据是"全仓引用计数"(源码 + tools/DbSmokeTest.java 等消费者一起数), 并用 javap -p 比对改前/改后 jar 的成员集合交叉验证:删除清单逐条一致、 新 jar 没有多出任何成员。

1.0.0 · 首个公开版本

Minecraft 1.12.2 · Forge · Pixelmon Reforged 8.4.3 的玩家交易市场:物品与宝可梦都能上架买卖, 挂单期间货品由市场托管,下架或过期原样退回。

市场界面

  • 6×5 = 30 个商品格子,卡片显示图标与价格(大额价格用 15M、1.2k 这类紧凑写法,完整金额在悬浮描述里);
  • 分类(全部 / 物品 / 宝可梦 / 我的在售)、排序(最新 / 价格升降 / 等级升降)、关键词搜索(回车立即搜,停笔也会自动搜);
  • 筛选:闪光、等级区间、价格区间、个体区间、特性、性格、性别、体型(全部由服务端过滤);
  • 右侧查看器:选中宝可梦后显示照片、等级/性格/特性/性别/个体/生命/携带与六边形雷达图;
  • 悬浮描述:鼠标指到货物上显示完整信息,内容可在配置里自定义([tooltip] 段);
  • 底部导航:浏览 / 我的在售 / 上架 / 历史 / 邮箱;所有按钮都有原版点击音效;
  • 按 J 或输入 /globalmarket open 打开界面。

上架

  • 上架物品:从背包 9×4 格子里选一格,填单价与数量;
  • 上架宝可梦:图形化列表(队伍优先,其次 PC),已在市场上的自动隐藏,队伍里的最后一只不能上架;
  • 按权限分配同时在售总数量:在 limits.permission-tiers 里写 权限节点=最大在售数(旧的双字段格式仍兼容), 不同权限组的玩家可以有不同的额度,命中多档时取最宽松的一档,0 表示不限制; 另有 globalmarket.bypass.limit 权限 = 完全不受数量限制。混合端读 Bukkit 权限(LuckPerms 等),纯 Forge 端读 Forge 权限;
  • 最大在售数、价格区间、物品/宝可梦黑名单、挂单过期时间都可以在配置里调。

交易与返还

  • 购买在服务端事务里完成:多人同时抢同一挂单只会成功一个,不会超卖;
  • 同一只宝可梦同时只能挂一次(由数据库保证);启动时会检查可疑的重复挂单并标记为暂停,交给管理员处理;
  • 不能购买自己的挂单(自己的挂单是"下架");
  • 邮箱:买家背包满、卖家离线、下架返还、回滚补偿、挂单过期都会进邮箱,支持单封领取与一键全部领取;
  • 邮箱界面按图标格子展示(6×4):物品带数量角标、宝可梦显示官方照片、钱显示金色金额,悬停看完整信息;
  • 交易历史:我的购买 / 我的出售(数量、单价、实付、税金、时间);
  • 服务端异常退出后遗留的未完成交易会在下次启动时自动恢复,挂单回到在售状态。

经济与权限

  • Vault:混合服务端(CatServer / Mohist 等)装了 Vault + 经济插件时自动使用 Vault(余额、扣款、收款、货币名都走它);
  • PokéDollars:纯 Forge 服务端自动使用 Pixelmon 自带货币,不需要任何配置;
  • 想强制某一种就把 economy.provider 写成 vault 或 pixelmon,强制 vault 但没挂上时会自动回退并打警告,服务器照常启动;
  • 权限节点:globalmarket.admin(管理员命令)、globalmarket.reload(重载配置)、 globalmarket.bypass.blacklist(不受黑名单限制)、globalmarket.bypass.limit(不受上架数量限制)。

数据库

  • 默认使用 SQLite 单文件 config/market.db,零配置,备份它等于备份市场;
  • 也可以使用 MySQL(database.type=mysql):多台服务器可共用一个市场, 连接参数在同一段配置(默认 127.0.0.1:3306、root、123456、库名 globalmarket),库不存在会自动创建; 需要 MySQL 5.7.6+ / MariaDB 10.2+,驱动用服务端自带的或放进 config/globalmarket/jdbc/;
  • 数据库结构随模组版本自动升级:只新增字段,不重建、不删数据,升级不会丢东西;
  • 服务器缺少 SQLite 驱动时,可换用同版本发布的"自带驱动"版本,并把 database.driver 设为 embedded(或 auto)。

命令

  • 玩家:/globalmarket open(开界面)、listings / items / pokemon / search / selling(聊天框查看)、 sell / sellpokemon / buy / cancel / history / mail / info;
  • 管理员:/globalmarket reload(重载配置)、/globalmarket admin ...(下架异常挂单、恢复暂停挂单、处理遗留交易、查看审计日志)、 /globalmarket version(查看版本、经济与数据库状态);
  • /globalmarket open <玩家> 可以为指定玩家打开界面(需要 OP);客户端版本过旧时会提示更新模组。

安装与升级须知

  • 客户端与服务端都要安装本模组,并且使用同一个 jar;两边版本不一致时客户端会提示"请更新模组";
  • 首次启动会生成 config/GlobalMarket.cfg 与数据库文件;
  • 升级模组时配置里已经废弃的选项会被自动清理,日志里会列出删了哪些;
  • 本模组不含 Pixelmon 的任何资源或代码,运行需要玩家自行安装 Pixelmon Reforged。