返回提交历史
Modified
src/services/worldStateService.ts
+131
-54
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
代码差异
1 个文件
+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);