XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

SpaceNinjaServer

A simple server for a small space ninja game

公开
关注 0 Fork 1 Star 0
返回提交历史

XFEstudio/SpaceNinjaServer

chore: use ideal time when going backwards to satisfy constraints (#2438)

"Before next expected world state refresh" is now used as a bare minimum constraint. If it cannot be met, we align to the ideal second. Compromising when multiple constraints are in use to avoid having to go back like 7 years, as this would break navigation. Closes #2434 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2438 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>

98ed2b5e
Sainan <63328889+Sainan@users.noreply.github.com>
提交于

代码差异

1 个文件 +131 -54
Modified src/services/worldStateService.ts +131 -54
@@ -1033,75 +1033,124 @@ const pushVoidStorms = (arr: IVoidStorm[], hour: number): void => {
1033 1033 }
1034 1034 };
1035 1035
1036 const doesTimeSatsifyConstraints = (timeSecs: number): boolean => {
1037 if (config.worldState?.eidolonOverride) {
1036 interface ITimeConstraint {
1037 //name: string;
1038 isValidTime: (timeSecs: number) => boolean;
1039 getIdealTimeBefore: (timeSecs: number) => number;
1040 }
1041
1042 const eidolonDayConstraint: ITimeConstraint = {
1043 //name: "eidolon day",
1044 isValidTime: (timeSecs: number): boolean => {
1038 1045 const eidolonEpoch = 1391992660;
1039 1046 const eidolonCycle = Math.trunc((timeSecs - eidolonEpoch) / 9000);
1040 1047 const eidolonCycleStart = eidolonEpoch + eidolonCycle * 9000;
1041 1048 const eidolonCycleEnd = eidolonCycleStart + 9000;
1042 1049 const eidolonCycleNightStart = eidolonCycleEnd - 3000;
1043 if (config.worldState.eidolonOverride == "day") {
1044 if (
1045 //timeSecs < eidolonCycleStart ||
1046 isBeforeNextExpectedWorldStateRefresh(timeSecs * 1000, eidolonCycleNightStart * 1000)
1047 ) {
1048 return false;
1049 }
1050 } else {
1051 if (
1052 timeSecs < eidolonCycleNightStart ||
1053 isBeforeNextExpectedWorldStateRefresh(timeSecs * 1000, eidolonCycleEnd * 1000)
1054 ) {
1055 return false;
1056 }
1050 return !isBeforeNextExpectedWorldStateRefresh(timeSecs * 1000, eidolonCycleNightStart * 1000);
1051 },
1052 getIdealTimeBefore: (timeSecs: number): number => {
1053 const eidolonEpoch = 1391992660;
1054 const eidolonCycle = Math.trunc((timeSecs - eidolonEpoch) / 9000);
1055 const eidolonCycleStart = eidolonEpoch + eidolonCycle * 9000;
1056 return eidolonCycleStart;
1057 }
1058 };
1059
1060 const eidolonNightConstraint: ITimeConstraint = {
1061 //name: "eidolon night",
1062 isValidTime: (timeSecs: number): boolean => {
1063 const eidolonEpoch = 1391992660;
1064 const eidolonCycle = Math.trunc((timeSecs - eidolonEpoch) / 9000);
1065 const eidolonCycleStart = eidolonEpoch + eidolonCycle * 9000;
1066 const eidolonCycleEnd = eidolonCycleStart + 9000;
1067 const eidolonCycleNightStart = eidolonCycleEnd - 3000;
1068 return (
1069 timeSecs >= eidolonCycleNightStart &&
1070 !isBeforeNextExpectedWorldStateRefresh(timeSecs * 1000, eidolonCycleEnd * 1000)
1071 );
1072 },
1073 getIdealTimeBefore: (timeSecs: number): number => {
1074 const eidolonEpoch = 1391992660;
1075 const eidolonCycle = Math.trunc((timeSecs - eidolonEpoch) / 9000);
1076 const eidolonCycleStart = eidolonEpoch + eidolonCycle * 9000;
1077 const eidolonCycleEnd = eidolonCycleStart + 9000;
1078 const eidolonCycleNightStart = eidolonCycleEnd - 3000;
1079 if (eidolonCycleNightStart > timeSecs) {
1080 // Night hasn't started yet, but we need to return a time in the past.
1081 return eidolonCycleNightStart - 9000;
1057 1082 }
1083 return eidolonCycleNightStart;
1058 1084 }
1085 };
1059 1086
1060 if (config.worldState?.vallisOverride) {
1087 const venusColdConstraint: ITimeConstraint = {
1088 //name: "venus cold",
1089 isValidTime: (timeSecs: number): boolean => {
1061 1090 const vallisEpoch = 1541837628;
1062 1091 const vallisCycle = Math.trunc((timeSecs - vallisEpoch) / 1600);
1063 1092 const vallisCycleStart = vallisEpoch + vallisCycle * 1600;
1064 1093 const vallisCycleEnd = vallisCycleStart + 1600;
1065 1094 const vallisCycleColdStart = vallisCycleStart + 400;
1066 if (config.worldState.vallisOverride == "cold") {
1067 if (
1068 timeSecs < vallisCycleColdStart ||
1069 isBeforeNextExpectedWorldStateRefresh(timeSecs * 1000, vallisCycleEnd * 1000)
1070 ) {
1071 return false;
1072 }
1073 } else {
1074 if (
1075 //timeSecs < vallisCycleStart ||
1076 isBeforeNextExpectedWorldStateRefresh(timeSecs * 1000, vallisCycleColdStart * 1000)
1077 ) {
1078 return false;
1079 }
1095 return (
1096 timeSecs >= vallisCycleColdStart &&
1097 !isBeforeNextExpectedWorldStateRefresh(timeSecs * 1000, vallisCycleEnd * 1000)
1098 );
1099 },
1100 getIdealTimeBefore: (timeSecs: number): number => {
1101 const vallisEpoch = 1541837628;
1102 const vallisCycle = Math.trunc((timeSecs - vallisEpoch) / 1600);
1103 const vallisCycleStart = vallisEpoch + vallisCycle * 1600;
1104 const vallisCycleColdStart = vallisCycleStart + 400;
1105 if (vallisCycleColdStart > timeSecs) {
1106 // Cold hasn't started yet, but we need to return a time in the past.
1107 return vallisCycleColdStart - 1600;
1080 1108 }
1109 return vallisCycleColdStart;
1081 1110 }
1111 };
1082 1112
1083 if (config.worldState?.duviriOverride) {
1084 const duviriMoods = ["sorrow", "fear", "joy", "anger", "envy"];
1085 const desiredMood = duviriMoods.indexOf(config.worldState.duviriOverride);
1086 if (desiredMood == -1) {
1087 logger.warn(`ignoring invalid config value for worldState.duviriOverride`, {
1088 value: config.worldState.duviriOverride,
1089 valid_values: duviriMoods
1090 });
1091 } else {
1092 const moodIndex = Math.trunc(timeSecs / 7200);
1093 const moodStart = moodIndex * 7200;
1094 const moodEnd = moodStart + 7200;
1095 if (
1096 moodIndex % 5 != desiredMood ||
1097 isBeforeNextExpectedWorldStateRefresh(timeSecs * 1000, moodEnd * 1000)
1098 ) {
1099 return false;
1100 }
1101 }
1113 const venusWarmConstraint: ITimeConstraint = {
1114 //name: "venus warm",
1115 isValidTime: (timeSecs: number): boolean => {
1116 const vallisEpoch = 1541837628;
1117 const vallisCycle = Math.trunc((timeSecs - vallisEpoch) / 1600);
1118 const vallisCycleStart = vallisEpoch + vallisCycle * 1600;
1119 const vallisCycleColdStart = vallisCycleStart + 400;
1120 return !isBeforeNextExpectedWorldStateRefresh(timeSecs * 1000, vallisCycleColdStart * 1000);
1121 },
1122 getIdealTimeBefore: (timeSecs: number): number => {
1123 const vallisEpoch = 1541837628;
1124 const vallisCycle = Math.trunc((timeSecs - vallisEpoch) / 1600);
1125 const vallisCycleStart = vallisEpoch + vallisCycle * 1600;
1126 return vallisCycleStart;
1102 1127 }
1128 };
1103 1129
1104 return true;
1130 const getIdealTimeSatsifyingConstraints = (constraints: ITimeConstraint[]): number => {
1131 let timeSecs = Math.trunc(Date.now() / 1000);
1132 let allGood;
1133 do {
1134 allGood = true;
1135 for (const constraint of constraints) {
1136 if (!constraint.isValidTime(timeSecs)) {
1137 //logger.debug(`${constraint.name} is not happy with ${timeSecs}`);
1138 const prevTimeSecs = timeSecs;
1139 const suggestion = constraint.getIdealTimeBefore(timeSecs);
1140 timeSecs = suggestion;
1141 do {
1142 timeSecs += 60;
1143 if (timeSecs >= prevTimeSecs || !constraint.isValidTime(timeSecs)) {
1144 timeSecs = suggestion; // Can't find a compromise; just take the suggestion and try to compromise on another constraint.
1145 break;
1146 }
1147 } while (!constraints.every(constraint => constraint.isValidTime(timeSecs)));
1148 allGood = false;
1149 break;
1150 }
1151 }
1152 } while (!allGood);
1153 return timeSecs;
1105 1154 };
1106 1155
1107 1156 const getVarziaRotation = (week: number): string => {
@@ -1179,10 +1228,38 @@ const getAllVarziaManifests = (): IPrimeVaultTraderOffer[] => {
1179 1228 };
1180 1229
1181 1230 export const getWorldState = (buildLabel?: string): IWorldState => {
1182 let timeSecs = Math.round(Date.now() / 1000);
1183 while (!doesTimeSatsifyConstraints(timeSecs)) {
1184 timeSecs -= 60;
1231 const constraints: ITimeConstraint[] = [];
1232 if (config.worldState?.eidolonOverride) {
1233 constraints.push(config.worldState.eidolonOverride == "day" ? eidolonDayConstraint : eidolonNightConstraint);
1234 }
1235 if (config.worldState?.vallisOverride) {
1236 constraints.push(config.worldState.vallisOverride == "cold" ? venusColdConstraint : venusWarmConstraint);
1237 }
1238 if (config.worldState?.duviriOverride) {
1239 const duviriMoods = ["sorrow", "fear", "joy", "anger", "envy"];
1240 const desiredMood = duviriMoods.indexOf(config.worldState.duviriOverride);
1241 if (desiredMood == -1) {
1242 logger.warn(`ignoring invalid config value for worldState.duviriOverride`, {
1243 value: config.worldState.duviriOverride,
1244 valid_values: duviriMoods
1245 });
1246 } else {
1247 constraints.push({
1248 //name: `duviri ${config.worldState.duviriOverride}`,
1249 isValidTime: (timeSecs: number): boolean => {
1250 const moodIndex = Math.trunc(timeSecs / 7200);
1251 return moodIndex % 5 == desiredMood;
1252 },
1253 getIdealTimeBefore: (timeSecs: number): number => {
1254 let moodIndex = Math.trunc(timeSecs / 7200);
1255 moodIndex -= ((moodIndex % 5) - desiredMood + 5) % 5; // while (moodIndex % 5 != desiredMood) --moodIndex;
1256 const moodStart = moodIndex * 7200;
1257 return moodStart;
1258 }
1259 });
1260 }
1185 1261 }
1262 const timeSecs = getIdealTimeSatsifyingConstraints(constraints);
1186 1263 const timeMs = timeSecs * 1000;
1187 1264 const day = Math.trunc((timeMs - EPOCH) / 86400000);
1188 1265 const week = Math.trunc(day / 7);