From c4aee5e53b06cccf4d1db1f7e10fb5059d86f6f3 Mon Sep 17 00:00:00 2001 From: ZHU MINCHAO <48154958+MinchaoZhu@users.noreply.github.com> Date: Wed, 4 Nov 2026 23:23:59 +0800 Subject: [PATCH] =?UTF-8?q?=E7=89=88=E6=9C=AC=201.0.0-rc3=EF=BC=9A?= =?UTF-8?q?=E6=89=8B=E5=86=8C=E5=8D=A0=E4=BD=8D=E7=AC=A6=E5=8F=96=E5=80=BC?= =?UTF-8?q?=E6=94=B9=E6=9F=A5=E8=A1=A8=EF=BC=8C=E6=89=AB=E6=8F=8F=E7=BB=93?= =?UTF-8?q?=E6=9E=9C=E6=97=A0=E6=9D=83=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 4 +- README.md | 2 +- src/Decentralized.Domain/TuningTable.cs | 436 ++++++++++++++++++++ src/Decentralized.Domain/TuningText.cs | 20 +- src/Decentralized/Core.cs | 2 +- src/Decentralized/ModFiles/manifest.xml | 2 +- tests/Decentralized.Domain.Tests/Program.cs | 35 +- 7 files changed, 479 insertions(+), 22 deletions(-) create mode 100644 src/Decentralized.Domain/TuningTable.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index c05d55a..c11ab7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ # Changelog -## 1.0.0-rc2 +## 1.0.0-rc3 -- 去掉反射:电子元件升级矿架时,原版元件工厂改用游戏公开的 `DirectoryMaster.GetFactory` 取得,清单恢复为不声明任何能力(rc1 因反射被游戏拒绝启用)。升级流程重新走通:普通 ×4 解锁第 3 槽,稀有 ×1 第 4 槽,稀有 ×2 第 5 槽。 +- 去掉反射:游戏的模组扫描把运行时反射算作未声明的权限,rc1 因此被拒绝启用。两处都改掉:电子元件升级矿架时,原版元件工厂改用游戏公开的 `DirectoryMaster.GetFactory` 取得;手册占位符取值(`TuningText`)从反射改成生成的查表(`TuningTable.cs`,单元测试核对它和 `Tuning` 一致)。清单不声明任何能力,扫描结果为无。升级流程重新走通:普通 ×4 解锁第 3 槽,稀有 ×1 第 4 槽,稀有 ×2 第 5 槽。 ## 1.0.0-rc1 diff --git a/README.md b/README.md index 1bc50a3..c97accb 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Probably Decentralized -A mod for *Probably Stolen*: crypto mining, a fictional coin market, stablecoins, laundering and its risks, a Web3 black market, built on the game's own power, events and law systems. Current version: 1.0.0-rc2 (release candidate). +A mod for *Probably Stolen*: crypto mining, a fictional coin market, stablecoins, laundering and its risks, a Web3 black market, built on the game's own power, events and law systems. Current version: 1.0.0-rc3 (release candidate). All coins, exchanges and events are fictional and have no real-world value. diff --git a/src/Decentralized.Domain/TuningTable.cs b/src/Decentralized.Domain/TuningTable.cs new file mode 100644 index 0000000..35dad1b --- /dev/null +++ b/src/Decentralized.Domain/TuningTable.cs @@ -0,0 +1,436 @@ +// 由测试项目生成:dotnet run --project tests/Decentralized.Domain.Tests -c Release -- --gen-tuning-table +// Tuning 增删数值后要重新生成(单元测试会核对)。 +using System; +using System.Collections.Generic; + +namespace Decentralized.Domain +{ + internal static class TuningTable + { + public static readonly Dictionary Scalars = new Dictionary + { + ["AirdropChance"] = Tuning.AirdropChance, + ["AirdropDays"] = Tuning.AirdropDays, + ["AirdropDrainMax"] = Tuning.AirdropDrainMax, + ["AirdropDrainMin"] = Tuning.AirdropDrainMin, + ["AirdropRewardMax"] = Tuning.AirdropRewardMax, + ["AirdropRewardMin"] = Tuning.AirdropRewardMin, + ["AirdropScam"] = Tuning.AirdropScam, + ["AmlBigRents"] = Tuning.AmlBigRents, + ["AmlCumRents"] = Tuning.AmlCumRents, + ["AmlExcessWeight"] = Tuning.AmlExcessWeight, + ["AmlHeavyRatio"] = Tuning.AmlHeavyRatio, + ["AmlMaxChance"] = Tuning.AmlMaxChance, + ["AmlMixerBonus"] = Tuning.AmlMixerBonus, + ["AmlTaintMult"] = Tuning.AmlTaintMult, + ["AmlTaintRatio"] = Tuning.AmlTaintRatio, + ["AmlWindowDays"] = Tuning.AmlWindowDays, + ["AsicChance"] = Tuning.AsicChance, + ["AsicDeadValue"] = Tuning.AsicDeadValue, + ["AsicNewShare"] = Tuning.AsicNewShare, + ["AsicRepM1"] = Tuning.AsicRepM1, + ["AsicRepM2"] = Tuning.AsicRepM2, + ["AsicRepM3"] = Tuning.AsicRepM3, + ["AsicRepairHealthCut"] = Tuning.AsicRepairHealthCut, + ["AsicUsedHealthMax"] = Tuning.AsicUsedHealthMax, + ["AsicUsedHealthMin"] = Tuning.AsicUsedHealthMin, + ["AsicWeightM1"] = Tuning.AsicWeightM1, + ["AsicWeightM2"] = Tuning.AsicWeightM2, + ["AsicWeightM3"] = Tuning.AsicWeightM3, + ["BlockReward"] = Tuning.BlockReward, + ["BmAdvanceDiscount"] = Tuning.BmAdvanceDiscount, + ["BmAdvanceMinTrades"] = Tuning.BmAdvanceMinTrades, + ["BmAutoSwapSlip"] = Tuning.BmAutoSwapSlip, + ["BmBulk1Count"] = Tuning.BmBulk1Count, + ["BmBulk1Discount"] = Tuning.BmBulk1Discount, + ["BmBulk2Count"] = Tuning.BmBulk2Count, + ["BmBulk2Discount"] = Tuning.BmBulk2Discount, + ["BmBulkChance"] = Tuning.BmBulkChance, + ["BmBulkDays"] = Tuning.BmBulkDays, + ["BmBulkQtyMax"] = Tuning.BmBulkQtyMax, + ["BmBulkQtyMin"] = Tuning.BmBulkQtyMin, + ["BmCommission"] = Tuning.BmCommission, + ["BmControlled"] = Tuning.BmControlled, + ["BmCoreMerchants"] = Tuning.BmCoreMerchants, + ["BmDoorDays"] = Tuning.BmDoorDays, + ["BmEliteChance"] = Tuning.BmEliteChance, + ["BmEliteDays"] = Tuning.BmEliteDays, + ["BmEliteGpuChance"] = Tuning.BmEliteGpuChance, + ["BmEliteGpuTier"] = Tuning.BmEliteGpuTier, + ["BmEliteListings"] = Tuning.BmEliteListings, + ["BmEliteMinValue"] = Tuning.BmEliteMinValue, + ["BmEliteQtyMax"] = Tuning.BmEliteQtyMax, + ["BmEscrowFee"] = Tuning.BmEscrowFee, + ["BmFactorBulkMax"] = Tuning.BmFactorBulkMax, + ["BmFactorBulkMin"] = Tuning.BmFactorBulkMin, + ["BmFactorEliteMax"] = Tuning.BmFactorEliteMax, + ["BmFactorEliteMin"] = Tuning.BmFactorEliteMin, + ["BmFactorMax"] = Tuning.BmFactorMax, + ["BmFactorMin"] = Tuning.BmFactorMin, + ["BmFactorNewMax"] = Tuning.BmFactorNewMax, + ["BmFactorNewMin"] = Tuning.BmFactorNewMin, + ["BmFactorUsedMax"] = Tuning.BmFactorUsedMax, + ["BmFactorUsedMin"] = Tuning.BmFactorUsedMin, + ["BmFakeDetect"] = Tuning.BmFakeDetect, + ["BmForumRugFactor"] = Tuning.BmForumRugFactor, + ["BmForumScamHint"] = Tuning.BmForumScamHint, + ["BmFreshRatingMax"] = Tuning.BmFreshRatingMax, + ["BmFreshRatingMin"] = Tuning.BmFreshRatingMin, + ["BmFreshTradesMax"] = Tuning.BmFreshTradesMax, + ["BmGpuChance"] = Tuning.BmGpuChance, + ["BmGpuFake"] = Tuning.BmGpuFake, + ["BmGpuMarkup"] = Tuning.BmGpuMarkup, + ["BmGpuNew"] = Tuning.BmGpuNew, + ["BmHighRep"] = Tuning.BmHighRep, + ["BmHonestFresh"] = Tuning.BmHonestFresh, + ["BmHoneypotBase"] = Tuning.BmHoneypotBase, + ["BmHoneypotDays"] = Tuning.BmHoneypotDays, + ["BmHoneypotMax"] = Tuning.BmHoneypotMax, + ["BmHoneypotPerSecRep"] = Tuning.BmHoneypotPerSecRep, + ["BmInterceptCrackdown"] = Tuning.BmInterceptCrackdown, + ["BmInterceptDoor"] = Tuning.BmInterceptDoor, + ["BmListFee"] = Tuning.BmListFee, + ["BmMaxListings"] = Tuning.BmMaxListings, + ["BmMaxUnitValue"] = Tuning.BmMaxUnitValue, + ["BmMerchantCount"] = Tuning.BmMerchantCount, + ["BmMerchantListings"] = Tuning.BmMerchantListings, + ["BmMidRep"] = Tuning.BmMidRep, + ["BmNewGpuQtyMaxCut"] = Tuning.BmNewGpuQtyMaxCut, + ["BmNewGpuQtyMinCut"] = Tuning.BmNewGpuQtyMinCut, + ["BmOldRatingMax"] = Tuning.BmOldRatingMax, + ["BmOldRatingMin"] = Tuning.BmOldRatingMin, + ["BmOldTradesMax"] = Tuning.BmOldTradesMax, + ["BmOldTradesMin"] = Tuning.BmOldTradesMin, + ["BmOpenRep"] = Tuning.BmOpenRep, + ["BmPersonalCount"] = Tuning.BmPersonalCount, + ["BmPersonalEliteShare"] = Tuning.BmPersonalEliteShare, + ["BmPersonalFactorMax"] = Tuning.BmPersonalFactorMax, + ["BmPersonalFactorMin"] = Tuning.BmPersonalFactorMin, + ["BmPersonalGpuChance"] = Tuning.BmPersonalGpuChance, + ["BmPersonalGpuNew"] = Tuning.BmPersonalGpuNew, + ["BmPersonalListings"] = Tuning.BmPersonalListings, + ["BmPersonalQtyMax"] = Tuning.BmPersonalQtyMax, + ["BmPersonalScam"] = Tuning.BmPersonalScam, + ["BmPremium"] = Tuning.BmPremium, + ["BmPriceJitter"] = Tuning.BmPriceJitter, + ["BmQtyMax"] = Tuning.BmQtyMax, + ["BmQtyMin"] = Tuning.BmQtyMin, + ["BmRatingFakeLoss"] = Tuning.BmRatingFakeLoss, + ["BmRatingStart"] = Tuning.BmRatingStart, + ["BmRefreshDays"] = Tuning.BmRefreshDays, + ["BmRepriceFee"] = Tuning.BmRepriceFee, + ["BmRugBase"] = Tuning.BmRugBase, + ["BmRugClosedDays"] = Tuning.BmRugClosedDays, + ["BmRugMax"] = Tuning.BmRugMax, + ["BmRugPerTenK"] = Tuning.BmRugPerTenK, + ["BmSaleHold"] = Tuning.BmSaleHold, + ["BmSaleTaintChanceMax"] = Tuning.BmSaleTaintChanceMax, + ["BmSaleTaintChanceMin"] = Tuning.BmSaleTaintChanceMin, + ["BmSaleTaintRatioMax"] = Tuning.BmSaleTaintRatioMax, + ["BmSaleTaintRatioMin"] = Tuning.BmSaleTaintRatioMin, + ["BmScamFresh"] = Tuning.BmScamFresh, + ["BmScamOldRatingMax"] = Tuning.BmScamOldRatingMax, + ["BmScamOldRatingMin"] = Tuning.BmScamOldRatingMin, + ["BmScamSellerShare"] = Tuning.BmScamSellerShare, + ["BmSellDay1Mult"] = Tuning.BmSellDay1Mult, + ["BmSellDays1"] = Tuning.BmSellDays1, + ["BmSellDaysFast"] = Tuning.BmSellDaysFast, + ["BmSellDaysMax"] = Tuning.BmSellDaysMax, + ["BmSellFastMult"] = Tuning.BmSellFastMult, + ["BmSellMax"] = Tuning.BmSellMax, + ["BmSellMin"] = Tuning.BmSellMin, + ["BmSellerBust"] = Tuning.BmSellerBust, + ["BmSpotQtyMax"] = Tuning.BmSpotQtyMax, + ["BmStockBase"] = Tuning.BmStockBase, + ["BmStockPerRep"] = Tuning.BmStockPerRep, + ["BmTechChance"] = Tuning.BmTechChance, + ["BmTechMarkup"] = Tuning.BmTechMarkup, + ["BmTrapDelay"] = Tuning.BmTrapDelay, + ["BmTrapShare"] = Tuning.BmTrapShare, + ["BmTrapWindowCap"] = Tuning.BmTrapWindowCap, + ["BmUnlockPrice"] = Tuning.BmUnlockPrice, + ["BmVolumeRef"] = Tuning.BmVolumeRef, + ["BmVolumeTaintMax"] = Tuning.BmVolumeTaintMax, + ["CardBracketScratch"] = Tuning.CardBracketScratch, + ["CardFanChipped"] = Tuning.CardFanChipped, + ["CardFanDust"] = Tuning.CardFanDust, + ["CardFingersDark"] = Tuning.CardFingersDark, + ["CardFingersOxidized"] = Tuning.CardFingersOxidized, + ["CardHealthMax"] = Tuning.CardHealthMax, + ["CardHealthMin"] = Tuning.CardHealthMin, + ["CardSealMissing"] = Tuning.CardSealMissing, + ["CardValueFloor"] = Tuning.CardValueFloor, + ["ChartVolCra"] = Tuning.ChartVolCra, + ["ChartVolCrc"] = Tuning.ChartVolCrc, + ["ChartVolCrt"] = Tuning.ChartVolCrt, + ["ChartVolMove"] = Tuning.ChartVolMove, + ["ChartVolPonero"] = Tuning.ChartVolPonero, + ["ChartVolPsc"] = Tuning.ChartVolPsc, + ["ChartVolSpark"] = Tuning.ChartVolSpark, + ["CoinPayCra"] = Tuning.CoinPayCra, + ["CoinPayCrc"] = Tuning.CoinPayCrc, + ["CoinPayCrt"] = Tuning.CoinPayCrt, + ["CoinPayPremium"] = Tuning.CoinPayPremium, + ["CoinPayPsc"] = Tuning.CoinPayPsc, + ["CraNpcStake"] = Tuning.CraNpcStake, + ["CraRate"] = Tuning.CraRate, + ["CraRateLow"] = Tuning.CraRateLow, + ["CraSpiralWeekly"] = Tuning.CraSpiralWeekly, + ["CraSubsidy0"] = Tuning.CraSubsidy0, + ["CraSubsidyWarn"] = Tuning.CraSubsidyWarn, + ["CraUnlockDays"] = Tuning.CraUnlockDays, + ["CraWarnLeadMax"] = Tuning.CraWarnLeadMax, + ["CraWarnLeadMin"] = Tuning.CraWarnLeadMin, + ["CrcDepegChance"] = Tuning.CrcDepegChance, + ["CrcDepegDaysMax"] = Tuning.CrcDepegDaysMax, + ["CrcDepegDaysMin"] = Tuning.CrcDepegDaysMin, + ["CrcDepegMax"] = Tuning.CrcDepegMax, + ["CrcDepegMin"] = Tuning.CrcDepegMin, + ["CrcHaircut"] = Tuning.CrcHaircut, + ["CrcHaircutChance"] = Tuning.CrcHaircutChance, + ["CrimeEventCap"] = Tuning.CrimeEventCap, + ["CrtDepegChance"] = Tuning.CrtDepegChance, + ["CrtDepegDaysMax"] = Tuning.CrtDepegDaysMax, + ["CrtDepegDaysMin"] = Tuning.CrtDepegDaysMin, + ["CrtDepegMax"] = Tuning.CrtDepegMax, + ["CrtDepegMin"] = Tuning.CrtDepegMin, + ["CrtFreezeBase"] = Tuning.CrtFreezeBase, + ["CrtFreezePerRep"] = Tuning.CrtFreezePerRep, + ["CrtFreezeShare"] = Tuning.CrtFreezeShare, + ["CrtSwapFee"] = Tuning.CrtSwapFee, + ["CrtUnfreezeAfter"] = Tuning.CrtUnfreezeAfter, + ["CustomerSpotChance"] = Tuning.CustomerSpotChance, + ["CustomerSpotTierMismatch"] = Tuning.CustomerSpotTierMismatch, + ["DealerAdvanced"] = Tuning.DealerAdvanced, + ["DealerAdvancedFromDay"] = Tuning.DealerAdvancedFromDay, + ["DealerAdvancedSecond"] = Tuning.DealerAdvancedSecond, + ["DealerFlagship"] = Tuning.DealerFlagship, + ["DealerFlagshipFromDay"] = Tuning.DealerFlagshipFromDay, + ["DealerRigRestock"] = Tuning.DealerRigRestock, + ["DealerSpecialFlagshipFromDay"] = Tuning.DealerSpecialFlagshipFromDay, + ["DeathBase"] = Tuning.DeathBase, + ["DeathWorn"] = Tuning.DeathWorn, + ["DexFee"] = Tuning.DexFee, + ["ElecPrice"] = Tuning.ElecPrice, + ["EraKjMult"] = Tuning.EraKjMult, + ["EraMax"] = Tuning.EraMax, + ["EraMin"] = Tuning.EraMin, + ["EraWarnMax"] = Tuning.EraWarnMax, + ["EraWarnMin"] = Tuning.EraWarnMin, + ["ExchangeFee"] = Tuning.ExchangeFee, + ["FakeDeathFactor"] = Tuning.FakeDeathFactor, + ["FakeSignChance"] = Tuning.FakeSignChance, + ["FakeSupportChance"] = Tuning.FakeSupportChance, + ["FakeTransferShare"] = Tuning.FakeTransferShare, + ["HalvingDays"] = Tuning.HalvingDays, + ["HalvingPassMax"] = Tuning.HalvingPassMax, + ["HalvingPassMin"] = Tuning.HalvingPassMin, + ["HalvingRamp"] = Tuning.HalvingRamp, + ["HalvingRampDays"] = Tuning.HalvingRampDays, + ["IntelBriefPrice"] = Tuning.IntelBriefPrice, + ["IntelFake"] = Tuning.IntelFake, + ["IntelRep"] = Tuning.IntelRep, + ["ManipBase"] = Tuning.ManipBase, + ["ManipFree"] = Tuning.ManipFree, + ["ManipFreezeDays"] = Tuning.ManipFreezeDays, + ["ManipMax"] = Tuning.ManipMax, + ["ManipSlope"] = Tuning.ManipSlope, + ["MixerCleanRate"] = Tuning.MixerCleanRate, + ["MixerFee"] = Tuning.MixerFee, + ["MixerMaxRounds"] = Tuning.MixerMaxRounds, + ["MixerMin"] = Tuning.MixerMin, + ["MixerNpcVolume"] = Tuning.MixerNpcVolume, + ["MixerRugChance"] = Tuning.MixerRugChance, + ["MixerSanctionChance"] = Tuning.MixerSanctionChance, + ["MixerSanctionDays"] = Tuning.MixerSanctionDays, + ["MixerUnlockPrice"] = Tuning.MixerUnlockPrice, + ["ModuleHashCap"] = Tuning.ModuleHashCap, + ["ModuleKjCap"] = Tuning.ModuleKjCap, + ["ModuleRatio"] = Tuning.ModuleRatio, + ["ModuleWearCap"] = Tuning.ModuleWearCap, + ["NpcAdj"] = Tuning.NpcAdj, + ["NpcHash0"] = Tuning.NpcHash0, + ["NpcKjPerH"] = Tuning.NpcKjPerH, + ["NpcTargetRatio"] = Tuning.NpcTargetRatio, + ["PerpAdlHaircut"] = Tuning.PerpAdlHaircut, + ["PerpBanDays"] = Tuning.PerpBanDays, + ["PerpDebtDays"] = Tuning.PerpDebtDays, + ["PerpDebtInterest"] = Tuning.PerpDebtInterest, + ["PerpDepthMult"] = Tuning.PerpDepthMult, + ["PerpFee"] = Tuning.PerpFee, + ["PerpFeeToFund"] = Tuning.PerpFeeToFund, + ["PerpFund0"] = Tuning.PerpFund0, + ["PerpFundCap"] = Tuning.PerpFundCap, + ["PerpFundCoef"] = Tuning.PerpFundCoef, + ["PerpFundDrift"] = Tuning.PerpFundDrift, + ["PerpFundShock"] = Tuning.PerpFundShock, + ["PerpLiqFee"] = Tuning.PerpLiqFee, + ["PerpMaint"] = Tuning.PerpMaint, + ["PerpOpenBuffer"] = Tuning.PerpOpenBuffer, + ["PerpPscCap"] = Tuning.PerpPscCap, + ["PerpPscLev"] = Tuning.PerpPscLev, + ["PerpShockFree"] = Tuning.PerpShockFree, + ["PerpSparkCap"] = Tuning.PerpSparkCap, + ["PerpSparkLev"] = Tuning.PerpSparkLev, + ["PoneroDailyCap"] = Tuning.PoneroDailyCap, + ["PoneroFee"] = Tuning.PoneroFee, + ["PoneroOpenRep"] = Tuning.PoneroOpenRep, + ["PoneroPscRatio"] = Tuning.PoneroPscRatio, + ["PonziAdCost"] = Tuning.PonziAdCost, + ["PonziBase0"] = Tuning.PonziBase0, + ["PonziBasePerDay"] = Tuning.PonziBasePerDay, + ["PonziCap0"] = Tuning.PonziCap0, + ["PonziCapPerDay"] = Tuning.PonziCapPerDay, + ["PonziCrime"] = Tuning.PonziCrime, + ["PonziMinDay"] = Tuning.PonziMinDay, + ["PonziRateExp"] = Tuning.PonziRateExp, + ["PonziReport0"] = Tuning.PonziReport0, + ["PonziReportRate"] = Tuning.PonziReportRate, + ["PonziReportSize"] = Tuning.PonziReportSize, + ["PonziWithdraw"] = Tuning.PonziWithdraw, + ["PoolDepth0"] = Tuning.PoolDepth0, + ["PoolFee"] = Tuning.PoolFee, + ["PredictCap"] = Tuning.PredictCap, + ["PredictDrift"] = Tuning.PredictDrift, + ["PredictFactionDaily"] = Tuning.PredictFactionDaily, + ["PredictFee"] = Tuning.PredictFee, + ["PredictFraudCap"] = Tuning.PredictFraudCap, + ["PredictFraudShare"] = Tuning.PredictFraudShare, + ["PredictGasBlind"] = Tuning.PredictGasBlind, + ["PredictHistory"] = Tuning.PredictHistory, + ["PredictInsiderCatch"] = Tuning.PredictInsiderCatch, + ["PredictInsiderShare"] = Tuning.PredictInsiderShare, + ["PredictLoss0"] = Tuning.PredictLoss0, + ["PredictLossPerDay"] = Tuning.PredictLossPerDay, + ["PredictMoveLog"] = Tuning.PredictMoveLog, + ["PredictNewPerDay"] = Tuning.PredictNewPerDay, + ["PredictNoise"] = Tuning.PredictNoise, + ["PredictOpenMax"] = Tuning.PredictOpenMax, + ["PredictOpenMin"] = Tuning.PredictOpenMin, + ["PredictPMax"] = Tuning.PredictPMax, + ["PredictPMin"] = Tuning.PredictPMin, + ["PredictUnlockDay"] = Tuning.PredictUnlockDay, + ["PriceCeiling"] = Tuning.PriceCeiling, + ["PriceFloor"] = Tuning.PriceFloor, + ["PscStartPrice"] = Tuning.PscStartPrice, + ["PscVol"] = Tuning.PscVol, + ["RefurbishHealth"] = Tuning.RefurbishHealth, + ["RepLossMax"] = Tuning.RepLossMax, + ["Revert"] = Tuning.Revert, + ["RigKj"] = Tuning.RigKj, + ["RigPrice"] = Tuning.RigPrice, + ["ScamMinDay"] = Tuning.ScamMinDay, + ["SentimentKappa"] = Tuning.SentimentKappa, + ["SentimentVol"] = Tuning.SentimentVol, + ["SideArbRate"] = Tuning.SideArbRate, + ["SideDepthShare"] = Tuning.SideDepthShare, + ["SparkFee"] = Tuning.SparkFee, + ["SparkMaxMult"] = Tuning.SparkMaxMult, + ["SparkMinMult"] = Tuning.SparkMinMult, + ["SparkRaidShock"] = Tuning.SparkRaidShock, + ["SparkRevert"] = Tuning.SparkRevert, + ["SparkStart"] = Tuning.SparkStart, + ["SparkUnrestShock"] = Tuning.SparkUnrestShock, + ["SparkVol"] = Tuning.SparkVol, + ["StoryBmCrtMult"] = Tuning.StoryBmCrtMult, + ["StoryCraSpiralMult"] = Tuning.StoryCraSpiralMult, + ["StoryLeakHaircutMult"] = Tuning.StoryLeakHaircutMult, + ["StoryLeakSpark"] = Tuning.StoryLeakSpark, + ["StoryLunDays"] = Tuning.StoryLunDays, + ["StoryLunMult"] = Tuning.StoryLunMult, + ["StoryReturnCrcMult"] = Tuning.StoryReturnCrcMult, + ["StoryRevSubsidy"] = Tuning.StoryRevSubsidy, + ["StorySecAmlMult"] = Tuning.StorySecAmlMult, + ["StorySecDays"] = Tuning.StorySecDays, + ["StorySecEnforceMult"] = Tuning.StorySecEnforceMult, + ["StorySecSanctionMult"] = Tuning.StorySecSanctionMult, + ["StorySerpicoSpark"] = Tuning.StorySerpicoSpark, + ["StorySparkNights"] = Tuning.StorySparkNights, + ["SupplyAdjust"] = Tuning.SupplyAdjust, + ["TaxRate"] = Tuning.TaxRate, + ["TumblerBmRep"] = Tuning.TumblerBmRep, + ["TumblerBounty"] = Tuning.TumblerBounty, + ["TumblerDriveValue"] = Tuning.TumblerDriveValue, + ["TumblerGift"] = Tuning.TumblerGift, + ["TumblerKeptFee"] = Tuning.TumblerKeptFee, + ["TumblerKeptVolume"] = Tuning.TumblerKeptVolume, + ["TumblerMinDay"] = Tuning.TumblerMinDay, + ["TumblerSecRep"] = Tuning.TumblerSecRep, + ["TumblerSellCrt"] = Tuning.TumblerSellCrt, + ["TumblerSoldFee"] = Tuning.TumblerSoldFee, + ["TumblerSoldRug"] = Tuning.TumblerSoldRug, + ["TxConfirmBase"] = Tuning.TxConfirmBase, + ["TxConfirmBig"] = Tuning.TxConfirmBig, + ["TxConfirmBigValue"] = Tuning.TxConfirmBigValue, + ["TxConfirmMid"] = Tuning.TxConfirmMid, + ["TxConfirmMidValue"] = Tuning.TxConfirmMidValue, + ["TxCongestedFeeMult"] = Tuning.TxCongestedFeeMult, + ["TxCongestedNormalSlow"] = Tuning.TxCongestedNormalSlow, + ["TxCongestedSlowSlow"] = Tuning.TxCongestedSlowSlow, + ["TxCongestionChance"] = Tuning.TxCongestionChance, + ["TxCongestionDaysMax"] = Tuning.TxCongestionDaysMax, + ["TxFeeFast"] = Tuning.TxFeeFast, + ["TxFeeNormal"] = Tuning.TxFeeNormal, + ["TxFeeSlow"] = Tuning.TxFeeSlow, + ["TxGasAmp"] = Tuning.TxGasAmp, + ["TxGasNoise"] = Tuning.TxGasNoise, + ["TxGasPeriod"] = Tuning.TxGasPeriod, + ["TxHijackChance"] = Tuning.TxHijackChance, + ["TxPhishChance"] = Tuning.TxPhishChance, + ["TxPoisonChance"] = Tuning.TxPoisonChance, + ["TxPoisonDelayMax"] = Tuning.TxPoisonDelayMax, + ["TxSlowDrop"] = Tuning.TxSlowDrop, + ["UnlockPrice"] = Tuning.UnlockPrice, + ["UsedFakeMiddleman"] = Tuning.UsedFakeMiddleman, + ["UsedFakeScammer"] = Tuning.UsedFakeScammer, + ["UsedFirstDay"] = Tuning.UsedFirstDay, + ["UsedMiddlemanHide"] = Tuning.UsedMiddlemanHide, + ["UsedMiddlemanMarkup"] = Tuning.UsedMiddlemanMarkup, + ["UsedMiddlemanShare"] = Tuning.UsedMiddlemanShare, + ["UsedScamBase"] = Tuning.UsedScamBase, + ["UsedScamMax"] = Tuning.UsedScamMax, + ["UsedScamPerDay"] = Tuning.UsedScamPerDay, + ["UsedVisitChance"] = Tuning.UsedVisitChance, + ["WalletDrainFull"] = Tuning.WalletDrainFull, + ["WalletDrainMin"] = Tuning.WalletDrainMin, + ["WalletDrainSlowDays"] = Tuning.WalletDrainSlowDays, + ["WalletJacksonChance"] = Tuning.WalletJacksonChance, + ["WalletJacksonPrice"] = Tuning.WalletJacksonPrice, + ["WalletMallChance"] = Tuning.WalletMallChance, + ["WalletMallMax"] = Tuning.WalletMallMax, + ["WalletMallMin"] = Tuning.WalletMallMin, + ["WalletMallQtyMax"] = Tuning.WalletMallQtyMax, + ["WalletMax"] = Tuning.WalletMax, + ["WalletPoisonShare"] = Tuning.WalletPoisonShare, + ["WickChance"] = Tuning.WickChance, + ["WickMax"] = Tuning.WickMax, + ["WickMin"] = Tuning.WickMin, + ["WickReal"] = Tuning.WickReal, + ["WickRevertMax"] = Tuning.WickRevertMax, + ["WickRevertMin"] = Tuning.WickRevertMin, + ["YieldCap0"] = Tuning.YieldCap0, + ["YieldCapPerDay"] = Tuning.YieldCapPerDay, + ["YieldLockDays"] = Tuning.YieldLockDays, + ["YieldPoolChance"] = Tuning.YieldPoolChance, + ["YieldPoolMax"] = Tuning.YieldPoolMax, + ["YieldReserveDays"] = Tuning.YieldReserveDays, + ["YieldRugNightly"] = Tuning.YieldRugNightly, + ["YieldScamAudit"] = Tuning.YieldScamAudit, + ["YieldScamTimelock"] = Tuning.YieldScamTimelock, + }; + + public static readonly Dictionary Arrays = new Dictionary + { + ["BmSellMults"] = Array.ConvertAll(Tuning.BmSellMults, v => (double)v), + ["CraSpiralPath"] = Array.ConvertAll(Tuning.CraSpiralPath, v => (double)v), + ["IntelTipAcc"] = Array.ConvertAll(Tuning.IntelTipAcc, v => (double)v), + ["IntelTipPrice"] = Array.ConvertAll(Tuning.IntelTipPrice, v => (double)v), + ["PonziRates"] = Array.ConvertAll(Tuning.PonziRates, v => (double)v), + ["SparkSpiralPath"] = Array.ConvertAll(Tuning.SparkSpiralPath, v => (double)v), + ["UsedHealthMax"] = Array.ConvertAll(Tuning.UsedHealthMax, v => (double)v), + ["UsedHealthMin"] = Array.ConvertAll(Tuning.UsedHealthMin, v => (double)v), + ["YieldRates"] = Array.ConvertAll(Tuning.YieldRates, v => (double)v), + ["YieldScamByRate"] = Array.ConvertAll(Tuning.YieldScamByRate, v => (double)v), + }; + } +} diff --git a/src/Decentralized.Domain/TuningText.cs b/src/Decentralized.Domain/TuningText.cs index 41852b5..57c95bb 100644 --- a/src/Decentralized.Domain/TuningText.cs +++ b/src/Decentralized.Domain/TuningText.cs @@ -1,6 +1,5 @@ using System; using System.Globalization; -using System.Reflection; using System.Text.RegularExpressions; namespace Decentralized.Domain @@ -42,24 +41,13 @@ namespace Decentralized.Domain private static bool TryValue(string path, int index, out double value) { value = 0; - var type = typeof(Tuning); - var parts = path.Split('.'); - for (int i = 0; i < parts.Length - 1; i++) - { - type = type.GetNestedType(parts[i], BindingFlags.Public | BindingFlags.Static); - if (type == null) return false; - } - var field = type.GetField(parts[parts.Length - 1], BindingFlags.Public | BindingFlags.Static); - if (field == null) return false; - var raw = field.GetValue(null); - if (raw is Array arr) + if (TuningTable.Arrays.TryGetValue(path, out var arr)) { if (index < 0 || index >= arr.Length) return false; - raw = arr.GetValue(index); + value = arr[index]; + return true; } - else if (index >= 0) return false; - try { value = Convert.ToDouble(raw, CultureInfo.InvariantCulture); return true; } - catch (Exception) { return false; } + return index < 0 && TuningTable.Scalars.TryGetValue(path, out value); } } } diff --git a/src/Decentralized/Core.cs b/src/Decentralized/Core.cs index 1868ed4..807a9fa 100644 --- a/src/Decentralized/Core.cs +++ b/src/Decentralized/Core.cs @@ -7,7 +7,7 @@ namespace Decentralized { public const string Id = "probably_decentralized"; public const string Name = "Probably Decentralized"; - public const string Version = "1.0.0-rc2"; + public const string Version = "1.0.0-rc3"; } /// 本地化:游戏的 mod 本地化表(ModFiles/Localization/*.csv),当前语言缺失时回退英文。 diff --git a/src/Decentralized/ModFiles/manifest.xml b/src/Decentralized/ModFiles/manifest.xml index 7bdfda4..8bb6206 100644 --- a/src/Decentralized/ModFiles/manifest.xml +++ b/src/Decentralized/ModFiles/manifest.xml @@ -3,7 +3,7 @@ probably_decentralized Probably Decentralized edward - 1.0.0-rc2 + 1.0.0-rc3 Mine PSC with graphics cards, trade it on a fictional exchange, and cash it out past the compliance desk. Work in progress. All coins, exchanges and events are fictional and have no real-world value. 0.46 diff --git a/tests/Decentralized.Domain.Tests/Program.cs b/tests/Decentralized.Domain.Tests/Program.cs index 011e929..7de36c4 100644 --- a/tests/Decentralized.Domain.Tests/Program.cs +++ b/tests/Decentralized.Domain.Tests/Program.cs @@ -26,8 +26,41 @@ internal static class Program private static bool Near(double a, double b, double tol) => Math.Abs(a - b) <= tol; - private static int Main() + /// 生成 TuningTable.cs:占位符取值走查表而不是运行时反射(游戏的模组扫描会把反射算作未声明的权限)。 + private static string GenerateTuningTable() { + var fields = typeof(Tuning).GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static) + .OrderBy(f => f.Name, StringComparer.Ordinal).ToList(); + var sb = new System.Text.StringBuilder(); + sb.Append("// 由测试项目生成:dotnet run --project tests/Decentralized.Domain.Tests -c Release -- --gen-tuning-table\n"); + sb.Append("// Tuning 增删数值后要重新生成(单元测试会核对)。\n"); + sb.Append("using System;\nusing System.Collections.Generic;\n\nnamespace Decentralized.Domain\n{\n"); + sb.Append(" internal static class TuningTable\n {\n"); + sb.Append(" public static readonly Dictionary Scalars = new Dictionary\n {\n"); + foreach (var f in fields.Where(f => !f.FieldType.IsArray)) sb.Append($" [\"{f.Name}\"] = Tuning.{f.Name},\n"); + sb.Append(" };\n\n public static readonly Dictionary Arrays = new Dictionary\n {\n"); + foreach (var f in fields.Where(f => f.FieldType.IsArray)) sb.Append($" [\"{f.Name}\"] = Array.ConvertAll(Tuning.{f.Name}, v => (double)v),\n"); + sb.Append(" };\n }\n}\n"); + return sb.ToString(); + } + + private static string FindRoot() => System.IO.Path.GetFullPath(System.IO.Path.Combine(AppContext.BaseDirectory, "../../../../..")); + + private static int Main(string[] args) + { + if (args.Contains("--gen-tuning-table")) + { + System.IO.File.WriteAllText(System.IO.Path.Combine(FindRoot(), "src/Decentralized.Domain/TuningTable.cs"), GenerateTuningTable().Replace("\r", "")); + Console.WriteLine("TuningTable.cs 已生成"); + return 0; + } + Test("占位符查表(TuningTable)和 Tuning 一致", () => + { + var path = System.IO.Path.Combine(FindRoot(), "src/Decentralized.Domain/TuningTable.cs"); + Check(System.IO.File.ReadAllText(path).Replace("\r", "") == GenerateTuningTable().Replace("\r", ""), "TuningTable.cs 已过期,重新生成:dotnet run --project tests/Decentralized.Domain.Tests -c Release -- --gen-tuning-table"); + var src = System.IO.File.ReadAllText(System.IO.Path.Combine(FindRoot(), "src/Decentralized.Domain/TuningText.cs")); + Check(!src.Contains("System.Reflection") && !src.Contains("GetField"), "TuningText 不用反射"); + }); Test("随机数:同种子同序列;状态可复制后继续", () => { var a = new Rng(42);