上一节把「自发行 vs 代理发行」算成了一道现金流比较题。这一节处理它最难的输入:分成比例从哪来。代理发行合同与谈判指南 那篇长文讲的是话术与条款——怎么开场、怎么还价、哪条不能签;本节不重复它,只做一件它没做的事:把「底线」算出来。底线不是拍脑袋的心理价位,而是从你的外部选项(自己干能挣多少)反推的一个数。《上线变现与长线运营》 给了你收入模型,本节把它接到谈判桌上。
谈判桌上真正在谈什么
外行以为谈判是「争一个百分比」。真实谈判争的是三个变量:分成比例、保底金额、以及发行商愿意投入多少买量(放大倍数)。这三者互相牵制——发行商愿意给高保底,往往是因为它想压低你的分成;它愿意高分成,往往是因为它不想承诺保底。所以谈判不是「要一个数」,是在这三个变量之间找平衡。
决定你能要到多少的,是筹码。筹码的作用不是「说服对方」,而是改变你自己的底线——你的底线越高,能接受的最低报价越高,谈判空间越大。
| 筹码 | 方向 | 为什么它值钱 |
|---|---|---|
| 自发行能力(自己会买量) | 抬底线 | 外部选项越强,越不需要发行商 |
| 游戏品质与留存 | 抬底线 | 好产品发行商抢着接,放大倍数更实 |
| 买量放大倍数的可验证性 | 抬底线 | 对方吹得越虚,你越该把底线定高 |
| 保底金额与兑现条件 | 抬底线 | 保底直接托住下限,等于降低风险 |
| 独家 / 多平台发行权 | 压底线 | 让出独家,就得用更高的分成补偿 |
| 发行期限长短 | 压底线 | 期限越长,锁死越久,越该要回报 |
前三项让你「敢走」——敢走才有议价权;后三项是你要让出的东西——每让一项,底线就该相应下调或换取对价。筹码清单的作用,是把模糊的「我感觉能要到 40%」变成可计算的「我的底线是 47.6%」。
底线怎么算:从外部选项反推
底线分成 floorSharePermille 的定义是:在发行商带来的放大倍数下,你最多能让出多少分成,仍能追平自发行。低于这个数你就不如自己干,高于这个数发行商就占你便宜。算法是从「自发行净收入」这个外部选项倒推:
selfNetFen = baselineGrossFen × platformNetPermille / 1000 − selfUaFen
fullShareNet = baselineGrossFen × upliftPermille / 1000 × platformNetPermille / 1000 # 分成为 0 时净收入
keepPermille = ceil( selfNetFen × 1000 / fullShareNet ) # 必须留下的千分比
floorSharePermille = 1000 − keepPermille # 可让出的最大分成=底线
keepPermille 是「至少得留下多少」,floorSharePermille 是它的补数,也就是你能接受的最大分成。放大倍数越高、自发行能力越弱,底线就越低(越能让),反之越高。注意这里是上取整((a + b − 1) // b)——留下的必须够,差一分都不行。
S 层:算底线与每个报价的安全边际
下面这段是 S 层仿真脚本 sim/o10_leverage.py。它读 config/o10_leverage.json 的三种发行能力情形与三个报价,算出每种情形的底线分成,再对每个报价算安全边际、判定是否接受、以及在保底兜底下的最终结果,产出 JSON + CSV + SVG。
#!/usr/bin/env python3
# file: sim/o10_leverage.py
# tier: S
# verify: /opt/homebrew/bin/python3 sim/o10_leverage.py --config config/ --out out/
"""分成谈判的底线模型:算出「最低可接受分成」与每个报价的安全边际。
读 config/o10_leverage.json。以中性流水 baselineGrossFen 为基准:
selfNetFen = baselineGrossFen * platformNetPermille // 1000 - selfUaFen
pubGrossFen = baselineGrossFen * upliftPermille // 1000
fullShareNet = pubGrossFen * platformNetPermille // 1000 # 发行商分成为 0 时的净收入
keepPermille = (selfNetFen * 1000 + fullShareNet - 1) // fullShareNet # 必须留下的千分比(上取整)
floorSharePermille = 1000 - keepPermille # 可让出的最大分成=底线
对每个报价 offerSharePermille:
devNetFen = max(minGuaranteeFen, fullShareNet * (1000 - offerSharePermille) // 1000)
marginPermille = floorSharePermille - offerSharePermille # 正=报价低于底线,按分成即达标
accept = devNetFen >= selfNetFen # 最终判据(保底可能让它翻盘)
needGuaranteeFen = selfNetFen # 保底至少要多少才能接受该报价
底线由「自发行净收入(外部选项)」反推:分成让出去多少,仍能追平自发行。
全程整数、地板除,无浮点。产出 out/o10_leverage.json + .csv + .svg。
放大倍数、自投成本、报价与保底都是「行业惯例」口径的建模假设;真实谈判过程需真实
业务环境,命令行不可复现(X)。本文不提供任何法律意见。
"""
from __future__ import annotations
import argparse
import csv
import json
import os
import xml.etree.ElementTree as ET
def load(d: str) -> dict:
with open(os.path.join(d, "o10_leverage.json"), encoding="utf-8") as f:
return json.load(f)
def case_floor(cfg: dict, case: dict) -> dict:
"""算一个情形的底线分成。"""
plat = cfg["platformNetPermille"]
self_net = cfg["baselineGrossFen"] * plat // 1000 - case["selfUaFen"]
pub_gross = cfg["baselineGrossFen"] * case["upliftPermille"] // 1000
full_share_net = pub_gross * plat // 1000
keep = (self_net * 1000 + full_share_net - 1) // full_share_net # 上取整
return {"caseId": case["id"], "caseName": case["name"], "upliftPermille": case["upliftPermille"],
"selfUaFen": case["selfUaFen"], "selfNetFen": self_net, "pubGrossFen": pub_gross,
"fullShareNetFen": full_share_net, "keepPermille": keep,
"floorSharePermille": 1000 - keep}
def evaluate_offer(floor: dict, offer: dict) -> dict:
"""一个报价相对某条底线的安全边际与判定。"""
dev_net_raw = floor["fullShareNetFen"] * (1000 - offer["publisherSharePermille"]) // 1000
dev_net = max(offer["minGuaranteeFen"], dev_net_raw)
margin = floor["floorSharePermille"] - offer["publisherSharePermille"]
return {"caseId": floor["caseId"], "offerId": offer["id"], "offerName": offer["name"],
"publisherSharePermille": offer["publisherSharePermille"], "minGuaranteeFen": offer["minGuaranteeFen"],
"devNetRawFen": dev_net_raw, "guaranteeBound": offer["minGuaranteeFen"] > dev_net_raw,
"devNetFen": dev_net, "selfNetFen": floor["selfNetFen"],
"marginPermille": margin, "accept": dev_net >= floor["selfNetFen"],
"needGuaranteeFen": floor["selfNetFen"]}
def draw_svg(path: str, floors: list[dict], offers: list[dict]) -> int:
"""纯 Python SVG:每个情形一根「底线分成」横条,叠加各报价竖线标记。"""
W, ROW, PAD = 760, 70, 210
H = 80 + ROW * len(floors)
root = ET.Element("svg", {"xmlns": "http://www.w3.org/2000/svg", "width": str(W),
"height": str(H), "viewBox": f"0 0 {W} {H}"})
ET.SubElement(root, "rect", {"width": str(W), "height": str(H), "fill": "#ffffff"})
ET.SubElement(root, "text", {"x": "16", "y": "28", "font-size": "15",
"fill": "#111827"}).text = "《合成小岛》各情形底线分成(千分比)· 竖线=报价"
span = W - PAD - 40
for i, fl in enumerate(floors):
y = 52 + i * ROW
w = span * fl["floorSharePermille"] // 1000
ET.SubElement(root, "text", {"x": "16", "y": str(y + 20), "font-size": "12",
"fill": "#374151"}).text = fl["caseName"]
ET.SubElement(root, "rect", {"x": str(PAD), "y": str(y + 6), "width": str(w), "height": "20",
"rx": "3", "fill": "#2563eb"})
ET.SubElement(root, "text", {"x": str(PAD + w + 6), "y": str(y + 21), "font-size": "11",
"fill": "#6b7280"}).text = f'底线 {fl["floorSharePermille"]}‰'
for o in offers:
x = PAD + span * o["publisherSharePermille"] // 1000
ET.SubElement(root, "line", {"x1": str(x), "y1": str(y + 2), "x2": str(x), "y2": str(y + 30),
"stroke": "#ef4444", "stroke-dasharray": "3 3"})
os.makedirs(os.path.dirname(path), exist_ok=True)
ET.ElementTree(root).write(path, encoding="utf-8", xml_declaration=True)
return len(ET.tostring(root))
def main() -> int:
ap = argparse.ArgumentParser()
ap.add_argument("--config", default="config/")
ap.add_argument("--out", default="out/")
a = ap.parse_args()
cfg = load(a.config)
floors = [case_floor(cfg, c) for c in cfg["cases"]]
floor_by_id = {f["caseId"]: f for f in floors}
verdicts = [evaluate_offer(floor_by_id[c["id"]], o) for c in cfg["cases"] for o in cfg["offers"]]
accepted = sum(1 for v in verdicts if v["accept"])
# 每情形被接受的报价集合,作为跨实现的确定性摘要。
digest = ";".join(
f'{f["caseId"]}:{f["floorSharePermille"]}:' +
",".join(v["offerId"] for v in verdicts if v["caseId"] == f["caseId"] and v["accept"])
for f in floors)
os.makedirs(a.out, exist_ok=True)
svg = draw_svg(os.path.join(a.out, "o10_leverage.svg"), floors, cfg["offers"])
with open(os.path.join(a.out, "o10_leverage.csv"), "w", encoding="utf-8", newline="") as f:
w = csv.writer(f)
cols = ("caseId", "offerId", "publisherSharePermille", "minGuaranteeFen", "devNetRawFen",
"guaranteeBound", "devNetFen", "selfNetFen", "marginPermille", "accept", "needGuaranteeFen")
w.writerow(cols)
for v in verdicts:
w.writerow([v[k] for k in cols])
report = {"version": cfg["version"], "game": cfg["game"], "observedAt": cfg["observedAt"],
"platformNetPermille": cfg["platformNetPermille"], "baselineGrossFen": cfg["baselineGrossFen"],
"floors": floors, "verdicts": verdicts, "acceptedCount": accepted,
"totalCount": len(verdicts), "digest": digest,
"svg": os.path.join(a.out, "o10_leverage.svg"), "svgBytes": svg}
with open(os.path.join(a.out, "o10_leverage.json"), "w", encoding="utf-8") as f:
json.dump(report, f, ensure_ascii=False, indent=2)
print(json.dumps({
"floors": [{"caseId": f["caseId"], "selfNet": f["selfNetFen"], "fullShareNet": f["fullShareNetFen"],
"keep": f["keepPermille"], "floorShare": f["floorSharePermille"]} for f in floors],
"verdicts": [{"caseId": v["caseId"], "offerId": v["offerId"], "share": v["publisherSharePermille"],
"devNet": v["devNetFen"], "margin": v["marginPermille"], "accept": v["accept"],
"guaranteeBound": v["guaranteeBound"]} for v in verdicts],
"acceptedCount": accepted, "digest": digest}, ensure_ascii=False, indent=2))
return 0
if __name__ == "__main__":
raise SystemExit(main())
参数放在 config/o10_leverage.json。放大倍数、自投成本、报价与保底都是「行业惯例」口径的建模假设:
{
"version": 1,
"game": "merge-island",
"observedAt": "2026-10",
"note": "分成谈判底线模型参数。口径是「行业惯例」的公开可观察机制,不是任何真实谈判或合同数据的实测,也不构成法律意见。platformNetPermille=平台扣成后可分成收入占比(千分比);baselineGrossFen=中性流水基准(分);cases[].upliftPermille=该情形下发行商买量把流水放大到的千分比;cases[].selfUaFen=自发行自己掏的买量预算(分);offers[].publisherSharePermille=发行商报价分成(千分比);offers[].minGuaranteeFen=报价附带的保底(分)。真实报价、真实放大倍数、真实谈判过程需真实业务环境,命令行不可复现(X)。全整数,无浮点。",
"platformNetPermille": 700,
"baselineGrossFen": 8000000,
"cases": [
{ "id": "weak", "name": "发行能力弱", "upliftPermille": 1200, "selfUaFen": 1600000 },
{ "id": "mid", "name": "发行能力中", "upliftPermille": 1500, "selfUaFen": 1200000 },
{ "id": "strong", "name": "发行能力强", "upliftPermille": 1900, "selfUaFen": 900000 }
],
"offers": [
{ "id": "o30", "name": "报价·分成30%", "publisherSharePermille": 300, "minGuaranteeFen": 0 },
{ "id": "o50", "name": "报价·分成50%", "publisherSharePermille": 500, "minGuaranteeFen": 2000000 },
{ "id": "o60", "name": "报价·分成60%", "publisherSharePermille": 600, "minGuaranteeFen": 3000000 }
]
}
在本机跑 /opt/homebrew/bin/python3 sim/o10_leverage.py --config config/ --out out/,三种发行能力下的底线与判定是(同机相对量级,绝对数值不可移植):
| 发行能力 | 自发行净(分) | 分成为0净(分) | 必留‰ | 底线分成‰ |
|---|---|---|---|---|
| 弱(放大 1.20×) | 4000000 | 6720000 | 596 | 404 |
| 中(放大 1.50×) | 4400000 | 8400000 | 524 | 476 |
| 强(放大 1.90×) | 4700000 | 10640000 | 442 | 558 |
再对三个报价逐一判定(安全边际为正表示报价低于底线,按分成即达标):
| 发行能力 | 报价 30% | 报价 50% | 报价 60% |
|---|---|---|---|
| 弱 | 接受(边际 +104) | 拒绝(边际 −96) | 拒绝(边际 −196,保底兜住) |
| 中 | 接受(边际 +176) | 拒绝(边际 −24) | 拒绝(边际 −124) |
| 强 | 接受(边际 +258) | 接受(边际 +58) | 拒绝(边际 −42) |
九格里接受 4 格。
读表:三种发行能力,三档底线
第一,发行能力越强,你的底线反而越高。 弱发行商底线只有 404‰,强发行商却高达 558‰——这看着反直觉,其实很合理:发行商越强,越能承受让利给你(它放大倍数高,池子大,让出一点绝对值也不亏)。所以面对强发行商,你反而可以更硬气,因为它离了你也愿意多给。
第二,保底能救回一个「不划算」的报价。 弱情形下的 60% 报价,按分成算只有 6720000 × 400 / 1000 = 2688000 分,远低于自发行的 4000000 分,marginPermille 是 −196,本该拒绝。但报价附带 3000000 分保底,max(3000000, 2688000) = 3000000 仍然不够——所以这一格最终还是拒绝。保底在弱情形下只把损失收窄,没能翻盘。真正的翻盘线是 needGuaranteeFen 那一列:保底至少要给到 4000000 分,60% 报价才可能被接受。谈判时这句话可以直接用:「分成 60% 可以谈,但保底得到 400 万分。」
第三,30% 报价在任何情形下都安全。 三档底线(404 / 476 / 558)都高于 300,所以 30% 是无条件可接受的。这也给出一个实用结论:先要一个稳赚的底价,再去争那 20 个点。
X 层:真实谈判过程不可复现
上面算的是模型侧:给定放大、成本、报价,底线与边际是多少。下面这些属于 X 层,需真实业务环境,命令行不可复现:
- 真实的放大倍数(发行商声称的与实际能交付的常有两回事,签约前无法验证);
- 真实的信息不对称(你未必知道发行商的底价、它也未必知道你的成本,谈判结果取决于双方的信息与关系);
- 真实的保底兑现条件(保底常附带「可回收 / 对赌 / 分期」条款,本节简化为一次性下限,这些附加条款的法律含义需咨询专业人士,本节不提供任何法律意见)。
工程上正确的做法是:把可复现的底线模型与不可复现的谈判过程分开。模型给你一条不可逾越的红线——低于底线就不签;红线以上是筹码的博弈区,靠的是你的自发行能力、产品品质、以及敢不敢走。红线之内怎么谈,是人的事,不是脚本的事。
自检表
| 检查项 | 合格标准 |
|---|---|
| 底线有来源 | 从「自发行净收入」外部选项反推,不拍脑袋 |
| 上取整正确 | 必留比例用 (a + b − 1) // b,留下的一定够 |
| 边际双算 | 既报分成边际,也报保底兜底后的最终判定 |
| 保底显形 | 标出保底是否兜底、以及「要多少保底才接受」 |
| 情形分层 | 至少弱 / 中 / 强三档发行能力,不只算一档 |
| 边界清晰 | 真实放大 / 信息 / 保底条款标 X,不写成「实测」;不提供法律意见 |
底线是谈判的锚,不是结论。它告诉你「低于这条线就走人」,但线以上的空间要靠筹码去撬。而筹码最终要落进一份合同——下一节我们就把「合同里到底该有哪些条款、怎么检查它写全了没有」清单化,做成一份可校验的齐备性检查。
阅读导航:上一节:10.1 自发行 vs 代理发行的决策 · 下一节:10.3 合同关键条款清单 。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。