实现详解)
前端图形学3D渲染【免费下载链接】Fantasy-Map-GeneratorWeb application generating interactive and highly customizable maps项目地址https://gitcode.com/gh_mirrors/fa/Fantasy-Map-Generator点击查看免费下载导读本文基于项目 PRD 文档 docs/prd/state-taxes-and-treasury.md系统讲解 Fantasy-Map-Generator 中国家税收与国库功能的完整设计与落地实现。该功能让地图中的每个国家通过销售税Sales Tax与人头税Poll Tax两种来源积累可序列化的国库余额state.treasury税率由国家政体state.form生成。读完本文你将掌握税率生成算法、本地/全球贸易中的征税流程、States.collectTaxes()的收税链路、States Editor 中国库编辑界面以及旧存档迁移规则并能在源码中定位每一处实现。配套领域文档 docs/domain/taxes.md 与本 PRD 相互印证本文同时给出源码级证据供读者在仓库中深入验证。一、背景旧税收模型的三个缺口原 PRD 明确指出旧模型存在两个核心问题外加一个衍生问题税率硬编码每个国家共享写死的salesTax 0.2与政治体制毫无关联税款蒸发销售税先从 burg 收入中扣除随后被直接丢弃——没有任何实体接收这笔钱跨市场贸易免税全球市场间贸易不征税导致大额长途贸易不产生任何国家收入国家也没有任何机制为财政国库、军事、行政提供资金。本 PRD 的解决思路是引入由两种税销售税 人头税喂养的国家国库税率在生成时由state.form决定。二、目标与非目标目标国家积累可序列化的国库余额销售税本地 全球归入卖方所在国家的国库新增人头税按每人口点计税税率在国家生成时由state.form生成逐国抖动jitter可在 States Editor 中编辑中立国state 0不缴税、不征税。非目标明确不做周期性/重复性经济运转——经济冻结在单次后生成周期支出机制腐败、行政、军费——标记为未来工作基于 type 或 formName 的税率修饰。三、数据模型变更State新增/变更三个持久化字段字段类型说明salesTaxnumber已存在现在由生成器产出不再固定为 0.2pollTaxnumber新增—— 每人口点征收的固定货币额treasurynumber新增—— 累积余额在 src/generators/states-generator.ts 的State接口中三个字段均为必填项salesTax: number; pollTax: number; treasury: number且createStates()与recreate()在建新状态时都以 0 初始化见 states-generator.ts。Neutralsstate 0同样以{ i: 0, name: Neutrals, salesTax: 0, pollTax: 0, treasury: 0 }初始化states-generator.ts。Deal新增一个可选持久化字段字段类型说明taxnumber可选该交易实际征收的销售税额货币单位Deal类型定义在 src/generators/markets-generator.tstax: number为必填局部交易填充 0但按 PRD 语义它仅在涉及跨市场交易时携带实际税额States.collectTaxes()对!deal.tax的交易直接跳过。四、税率生成从政体到抖动税率生成公式在国家生成时每个国家的税率从以下公式抽取rate round(gauss(base, base × 0.15, base × 0.5, base × 1.5), 2)gauss的四个参数分别对应均值、标准差下界、标准差上界与裁剪范围结果四舍五入到两位小数。源码实现位于 src/generators/states-generator.ts 的defineTaxRates(state)defineTaxRates(state: State) { const { salesTax, pollTax } DEFAULT_TAX_BY_FORM[state.form || ] || DEFAULT_TAX; return { salesTax: rn(gauss(salesTax, salesTax * 0.15, salesTax * 0.5, salesTax * 1.5, 4), 2), pollTax: rn(gauss(pollTax, pollTax * 0.15, pollTax * 0.5, pollTax * 1.5, 4), 2) }; }政体基准税率表政体Form销售税基准Sales Tax base人头税基准Poll Tax baseMonarchy0.150.20Theocracy0.250.10Union0.070.13Republic0.050.15Anarchy0.000.00基准表在源码中对应 states-generator.ts 的DEFAULT_TAX_BY_FORM常量缺省回退到Monarchy基准DEFAULT_TAX。Anarchy 的基准为 0高斯分布坍缩因此严格保持为 0。中立国state 0的两种税率无条件为 0。与政体分配流程的耦合税率并非独立生成而是在defineStateForms()确定state.form后同步分配states-generator.tsconst taxes this.defineTaxRates(s); s.salesTax taxes.salesTax; s.pollTax taxes.pollTax;注意defineStateForms还会把政体细化为formName如 Duchy、Kingdom、Trade Company、Caliphate 等但按非目标声明税率只与粗粒度form挂钩formName不参与税率修饰。五、销售税机制销售税作用于两类交易本地销售burg → market与全球销售market → market。5.1 本地销售burg → market本地销售此前已作为对 burg 收入的扣除实现行为保持不变tax state.salesTax × units × dealPrice burg.treasury - grossRevenue // 既有 burg.treasury (grossRevenue − tax) // 既有实现证据位于 src/generators/production-generator.tsStates.getSalesTax(state.burg)解析税率Markets.sell()生成交易并计算tax随后生产模块按grossRevenue deal.units * deal.price、taxAmount deal.tax ?? grossRevenue * taxRate、revenue grossRevenue - taxAmount记账。Markets.sell()本体在 src/generators/markets-generator.tssell({ burg, good, units, taxRate }: { burg: Burg; good: Good; units: number; taxRate: number }): Deal | null { const market this.get(burg.market); if (!market || units 0) return null; const marketGood this.getMarketGood(market, good); const price this.customerSellPrice(marketGood.price); const tax rn(units * price * taxRate, 2); // ... 构造 Dealtax 字段携带税额 return deal; }tax被记录在Deal.tax上这样States.collectTaxes()之后可以直接入账而无需重新解析税率——这正是 PRD 强调记录而非重算的设计。States.getSalesTax(burg)在 states-generator.ts 实现中立 burg 的 state 为 0 时返回 0否则查pack.states[stateId].salesTax查不到回退 0。5.2 全球销售market → market全球贸易的税额加进到岸成本landed cost在Markets.runGlobalTrade()的盈利检查中生效exporterTaxPerUnit exporterState.salesTax × exporterPrice landedCost exporterPrice transportCost exporterTaxPerUnit unitProfit importerPrice − landedCost源码在 src/generators/markets-generator.tsconst exporterCenter pack.burgs[exporter.market.centerBurgId]; const exporterTaxPerUnit States.getSalesTax(exporterCenter) * exporterGood.price; // ... const transportCost distances[importer.market.i] * good.value; const unitProfit importerGood.price - (exporterGood.price transportCost exporterTaxPerUnit); const totalProfit unitProfit * units; if (totalProfit MIN_PROFIT) continue;若交易最终执行Deal 记录price landedCost进口方实际承担的每单位成本tax exporterTaxPerUnit × units见 markets-generator.ts。经济后果高税率国家因此成为更差的出口方——其出口商品的到岸成本更高totalProfit MIN_PROFIT的机会被直接跳过利润空间的opportunities排序按totalProfit降序也会自动压低高税国家的成交优先级。参数调优提示PRD 明确指出全球贸易的盈利常量可能需要重新调校以抵消新增摩擦MIN_PROFIT 1见 markets-generator.tsDISTANCE_COST_FACTOR 1markets-generator.ts运输成本 (距离/地图对角线) × DISTANCE_COST_FACTOR见 L430。运输成本还与good.value相乘distances[importer.market.i] * good.value因此远程大宗商品运输叠加出口税后利润门槛更敏感。5.3 定价与动画影响记录下的全球贸易price上移包含了税额。trade-details 对话框读取deal.price × units作为交易总额此数值现在反映进口方实际支付含出口国税收毛额。出口方的名义所得为price − transportCost/unit − tax/unit但市场没有国库所以这个数值仅作展示信息。相关控制器src/controllers/markets-overview.ts——对 market→market 交易改为直接读取deal.tax不再用 burg 税率二次推导src/controllers/production-overview.ts——getDealTax(deal)可直接读deal.tax。六、人头税机制人头税是单一后处理周期的追加revenue state.pollTax × (state.rural state.urban) state.treasury revenue实现见 src/generators/states-generator.tsfor (const state of states) { if (!state.i || state.removed) continue; const population (state.rural || 0) (state.urban || 0); state.treasury rn(state.treasury state.pollTax * population, 2); }state.rural与state.urban由collectStatistics()累计states-generator.ts遍历陆地格rural cells.pop[i]若格上有 burg 则urban burg.population。人头税不从任何 burg 或乡村来源扣款——钱凭空出现这与冻结周期frozen-tick模型一致恰好反转了旧模型贸易税收入蒸发的方向。七、States.collectTaxes()唯一国库写入者StatesModule新增的collectTaxes()方法src/generators/states-generator.ts是生成器侧唯一写入state.treasury的地方。其流程与 PRD 完全一致对每个i 0且未移除的国家重置treasury 0遍历pack.dealsdeal.sellerType burg将deal.tax计入pack.burgs[deal.seller].state所属国家的 treasurydeal.sellerType market计入出口市场中心 burg所属国家的 treasury经Markets.get(deal.seller).centerBurgId解析见 states-generator.ts无tax的交易如买入、需求补货贡献 0对每个非中立国家treasury pollTax × (rural urban)结果用rn(..., 2)四舍五入跳过 state 0中立国——国库恒为 0。调用时机PRD 要求在public/main.js中Production.produce()之后调用。当前源码中ProductionModule.regenerate()在produce()后立即调用States.collectTaxes()src/generators/production-generator.ts而produce()内部依次执行Markets.collectRuralProduction()、Markets.initializeMarketPrices()、本地销售与Markets.runGlobalTrade()从而保证pack.deals全部就绪后再统一收税。测试佐证src/generators/states-generator.test.ts 对collectTaxes有针对性覆盖构造 state 1salesTax 0.2、pollTax 0.5、rural 100、urban 50与 state 2salesTax 0.1、pollTax 0.1、rural 200、urban 100混合本地 burg 卖家与市场卖家交易后断言state 1销售税 10 2 12人头税 0.5 × 150 75国库 87state 2销售税 1.2人头税 0.1 × 300 30国库 31.2state 0国库恒为0。第二个用例L128-L154验证无交易、无人头税时国库保持 0以及中立国边界行为。八、States EditorTreasury 列与对话框新 Treasury 列States Editor 在 src/controllers/states-editor.ts 注册了新列key: treasury, tip: Click to sort by state treasury. Click on a value to view and edit taxes, sortBy: s s.treasury || 0单元格为只读文本显示state.treasury渲染为 图标 金额见 L426点击单元格打开该国 Treasury 对话框openTreasuryDialog(stateId)L872中立国state 0渲染为占位符tooltip 提示 Neutrals collect no taxesL364。Treasury 对话框字段清单对应 states-editor.ts 的 HTML 模板字段可编辑说明Sales Tax rate是min0 max1 step0.010.00–1.00Poll Tax rate是min0 max10 step0.010.00–10.00上界宽松可调Treasury balance是step1手动覆盖值Breakdown — Sales Tax revenue否由pack.deals中该国家作为卖方征收的deal.tax求和L877-L888解析逻辑与collectTaxes()完全一致Breakdown — Poll Tax revenue否pollTax × (rural urban)L876对话框保存逻辑L907-L913将编辑后的treasury写入state.treasury rn(newTreasury, 2)同时写入两个税率tooltip 明确提示Tax changes take effect on Production regeneration税率修改在下次生产再生成时生效。PRD 中提及的 Regenerate Production 按钮属于 TODO尚未构建。注意语义边界手填的国库余额是对国家资产的断言不会反向重算生产、交易或关联 burg 的余额——编辑器是collectTaxes()之外唯一允许写state.treasury的入口。Burg.treasury在 Burg Editor 中同样可直接编辑下次生产运行覆盖见 docs/domain/taxes.md 说明。九、向后兼容旧存档迁移迁移逻辑位于 src/services/io/auto-update.tsstate.treasury缺失 → 置为0state.pollTax缺失 → 依据政体基准表回填States.defineTaxRates(state)加载时不抖动源码中迁移路径直接调用defineTaxRates其结果本身包含与生成时相同的 gauss 抖动——见下方说明state.salesTax存在 →覆盖为基准表生成值。具体迁移代码state.salesTax 0; state.pollTax 0; state.treasury 0; // ... const taxes States.defineTaxRates(state); state.salesTax taxes.salesTax; state.pollTax taxes.pollTax; state.treasury 0;迁移语义PRD 与 docs/domain/taxes.md 共同确认旧存档会被重平衡到新模型玩家保留世界但失去旧 regime固定 0.2下手工编辑的每国销售税——自定义税率被覆盖defineTaxRates使用与新建国家完全相同的 gauss 公式因此同一个世界在首次迁移后重复加载税率保持稳定但首次加载 pre-migration 存档得到的税率与旧的硬编码 0.2 不同迁移后 States Editor 在下一次生产运行后显示非零国库。十、验收标准Acceptance Criteria按 PRD 原文以下六项构成功能完成的判定基准重新生成后每个非中立国家都拥有由政体推导、逐国抖动的非零salesTax与pollTax生产后任一非中立国家的state.treasury等于sum(deal.tax for deals where sellers state this state) pollTax × (rural urban)全球贸易交易携带deal.taxrunGlobalTrade会跳过那些加入出口税后不再盈利的机会中立国state 0国库保持 0且中立 burg 的交易不征税加载旧.map后按迁移规则填充三个新/变更字段States Editor 在下一次生产运行后显示非零国库States Editor 显示 Treasury 列点击打开可编辑税率与国库覆盖值的对话框。第 2、4 条已由 src/generators/states-generator.test.ts 的用例直接验证见第七节其余条目可在完成生产再生成后人工核验。十一、未来工作与范围外事项PRD 明确列出的后续方向Regenerate Production 操作——编辑器 tooltip 已引用尚未构建支出机制——腐败等级、行政成本、军费从国库扣除周期性经济运转——年度循环、国库累积、人口增长反馈formName/type 修饰——更细粒度税率如 Trade Republic ≠ Most Serene Republic进口关税——本 PRD 仅实现出口方税。十二、文件影响清单附仓库路径核心实现src/generators/states-generator.ts——DEFAULT_TAX_BY_FORM基准表、defineTaxRates()、collectTaxes()、State接口扩展src/generators/markets-generator.ts——Deal.tax字段、sell()本地税、runGlobalTrade()出口税入到岸成本src/generators/production-generator.ts——本地销售税扣款、regenerate()内调用States.collectTaxes()src/controllers/states-editor.ts——Treasury 列、Treasury 对话框、收入明细src/controllers/markets-overview.ts、src/controllers/production-overview.ts——改为读取deal.taxsrc/services/io/auto-update.ts——salesTax/pollTax/treasury迁移。测试src/generators/states-generator.test.ts——collectTaxes单状态、混合本地/全球交易、人头税入账、中立国边界src/generators/markets-generator.test.ts——全球贸易税影响到岸成本、交易记录tax。文档docs/domain/taxes.md——新增领域文档税收来源、税率生成、收税流程、编辑器表面、迁移说明docs/domain/glossary.md——新增 Treasury、Sales Tax、Poll Tax 词条docs/domain/trade_schema.md——更新销售阶段/全球再分配章节移除跨市场贸易无销售税表述docs/architecture/data-model.md——State增加三字段、Deal增加tax?。结语从 docs/prd/state-taxes-and-treasury.md 的构思到 src/generators/states-generator.ts 的collectTaxes()落地这套税收与国库系统完成了税款从交易中产生 → 记录在deal.tax→ 汇总进卖方国家 treasury 人头税追加的完整闭环同时通过政体基准表 gauss 抖动让每个国家获得差异化、可编辑、可迁移的财政参数。理解这条链路是后续实现军费、行政开销与年度经济循环等扩展功能的起点。赞分享前端图形学3D渲染【免费下载链接】Fantasy-Map-GeneratorWeb application generating interactive and highly customizable maps项目地址https://gitcode.com/gh_mirrors/fa/Fantasy-Map-Generator点击查看免费下载相关推荐3个GPT提示词模板跑通学术写作论文提纲、文献翻译与思路拓展完整指南3个GPT提示词模板跑通学术写作论文提纲、文献翻译与思路拓展完整指南 不用从零设计提示词也能搭好一套学术写作工作流。下面用 awesome prompts前端图形学3D渲染Fantasy-Map-Generator外交系统终极指南如何打造完美国家关系与联盟管理Fantasy Map Generator外交系统终极指南如何打造完美国家关系与联盟管理 Fantasy Map Generator是一款功能强大的Web应用前端图形学3D渲染终极指南Fantasy-Map-Generator字体系统与文本渲染技术详解终极指南Fantasy Map Generator字体系统与文本渲染技术详解 Fantasy Map Generator是一个功能强大的Web应用程序专注于前端图形学3D渲染上一篇三分钟扫码备份QQ空间GetQzonehistory 把历史说说全部抓回本地下一篇Virtual Display DriverWindows虚拟显示器扩展的终极指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考