using System; using System.Numerics; using UnityEditor; using UnityEngine; using VS.Sim; namespace VS.EditorTools { // 진행 속도 측정: -executeMethod VS.EditorTools.HeadlessRun.Balance (자동 플레이어 = 1 초 1탭 + 하이프 탭 5회/초 · 30 초마다 후원 받기 · 가장 싼 구매) public static partial class HeadlessRun { public static void Balance() { int exit = 0; try { Application.SetStackTraceLogType(LogType.Log, StackTraceLogType.None); var t = LoadTables(); double hours = 12; var env = Environment.GetEnvironmentVariable("VS_HOURS"); if (!string.IsNullOrEmpty(env)) double.TryParse(env, out hours); var g = NewGame(t, out var clk); float dt = 0.2f; double nextDonate = 30, nextLog = 600; int lastRank = g.S.rankIndex, lastHouse = g.S.house; long buys = 0; for (double tm = 0; tm < hours * 3600; tm += dt) { g.Tap(); g.Tick(dt); if (g.Time >= nextDonate) { g.ClaimDonate(1); nextDonate += 30; } if (g.RankUpPending) g.ApplyRankUp(); for (int k = 0; k < 20; k++) { if (!BuyCheapest(g)) break; buys++; } if (g.CanBuyNextHouse()) g.BuyNextHouse(); if (g.S.rankIndex != lastRank) { Debug.Log($"[VS] BAL t={g.Time / 60:0.0}m rank {lastRank}->{g.S.rankIndex} follower={g.Follower}"); lastRank = g.S.rankIndex; } if (g.S.house != lastHouse) { Debug.Log($"[VS] BAL t={g.Time / 60:0.0}m house {lastHouse + 1}->{g.S.house + 1}"); lastHouse = g.S.house; } if (g.Time >= nextLog) { nextLog += 1800; Debug.Log($"[VS] BAL t={g.Time / 60:0}m coin={g.Coin} pass/s={g.PassGps():0.###} tap={g.TapGps():0.###} house={g.S.house + 1} rank={g.S.rankIndex} buys={buys}"); } } Debug.Log($"[VS] BALANCE DONE hours={hours} house={g.S.house + 1} rank={g.S.rankIndex} follower={g.Follower} coin={g.Coin} buys={buys}"); } catch (Exception e) { Debug.LogError("[VS] EXCEPTION " + e); exit = 2; } EditorApplication.Exit(exit); } static bool BuyCheapest(Game g) { int bestType = -1; bool bestSkill = false; BigInteger best = BigInteger.Zero; foreach (var it in g.Room.Items) { if (!g.RoomUnlocked(it.Index) || g.RoomMaxed(it.Index) || g.RoomUpgrading(it.Index)) continue; var p = g.RoomNextPrice(it.Index); if (p <= g.Coin && (bestType < 0 || p < best)) { best = p; bestType = it.Index; bestSkill = false; } } foreach (var it in g.T.Skills.Items) { if (!g.CanBuySkill(it.Index) || g.SkillUpgrading(it.Index)) continue; var p = g.SkillNextPrice(it.Index); if (p <= g.Coin && (bestType < 0 || p < best)) { best = p; bestType = it.Index; bestSkill = true; } } if (bestType < 0) return false; return (bestSkill ? g.BuySkill(bestType) : g.BuyRoomItem(bestType)) == BuyResult.Ok; } } }