• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

DaniSomoza / galactic-commander / 12422152220

19 Dec 2024 10:57PM UTC coverage: 52.396% (-13.2%) from 65.587%
12422152220

Pull #11

github

web-flow
Merge e0cd6a508 into 4f9f087f0
Pull Request #11: Build units

204 of 768 branches covered (26.56%)

Branch coverage included in aggregate %.

363 of 886 new or added lines in 84 files covered. (40.97%)

10 existing lines in 7 files now uncovered.

1414 of 2320 relevant lines covered (60.95%)

3.83 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.44
/packages/game-engine/src/engine/processTasks.ts
1
import { MongoServerError } from 'mongodb'
2

3
import {
4✔
4
  TaskType,
5
  ERROR_TASK_STATUS,
6
  FINISH_RESEARCH_TASK_TYPE,
7
  FinishResearchTaskData,
8
  NEW_PLAYER_TASK_TYPE,
9
  PROCESSED_TASK_STATUS,
10
  START_RESEARCH_TASK_TYPE,
11
  StartResearchTaskData,
12
  TaskData,
13
  FINISH_BUILD_UNITS_TASK_TYPE,
14
  START_BUILD_UNITS_TASK_TYPE,
15
  FinishBuildUnitsTaskData,
16
  StartBuildUnitsTaskData
17
} from '../types/ITask'
18
import taskRepository from '../repositories/taskRepository'
4✔
19
import playerRepository from '../repositories/playerRepository'
4✔
20
import groupTasksBySeconds from '../helpers/groupTasksBySeconds'
4✔
21
import { IPlanetDocument } from '../models/PlanetModel'
22
import { IPlayerDocument } from '../models/PlayerModel'
23
import { IUniverseDocument } from '../models/UniverseModel'
24
import { ITaskDocument, ITaskTypeDocument } from '../models/TaskModel'
25
import { TASK_HANDLER, TaskHandler } from './tasks/taskHandlers'
4✔
26
import calculateResourceProduction from './resources/calculateResourceProduction'
4✔
27
import computedBonus from './bonus/computedBonus'
4✔
28
import GameEngineError from './errors/GameEngineError'
4✔
29

30
async function processTasks(tasks: ITaskDocument[], universe: IUniverseDocument) {
31
  const tasksGroupedBySeconds = groupTasksBySeconds(tasks, universe)
23✔
32

33
  for (const { tasks, second } of tasksGroupedBySeconds) {
23✔
34
    // 0.- Calculate player resources
35
    await processResourceProduction(tasks, second)
23✔
36

37
    // 1.- New player Tasks
38
    const newPlayerTasks = tasks.filter((task) => task.type === NEW_PLAYER_TASK_TYPE)
23✔
39

40
    const newPlayerTaskHandler = TASK_HANDLER[NEW_PLAYER_TASK_TYPE].handler
23✔
41

42
    await processTasksSequentially(newPlayerTasks, newPlayerTaskHandler, second)
23✔
43

44
    // 2.- Finish Research Tasks
45
    const finishResearchTaskHandler = TASK_HANDLER[FINISH_RESEARCH_TASK_TYPE].handler
23✔
46

47
    const finishResearchTasks = tasks.filter((task) => task.type === FINISH_RESEARCH_TASK_TYPE)
23✔
48
    await processTasksInParallel(finishResearchTasks, finishResearchTaskHandler, second)
23✔
49

50
    // 3.- Start Research Tasks
51
    const startResearchTaskHandler = TASK_HANDLER[START_RESEARCH_TASK_TYPE].handler
23✔
52

53
    // we can have new startResearchTasks generated by the finishResearchTaskHandler
54
    const startResearchTasks = await taskRepository.getPendingTasksByType(
23✔
55
      universe._id,
56
      second,
57
      START_RESEARCH_TASK_TYPE
58
    )
59
    await processTasksSequentially(startResearchTasks, startResearchTaskHandler, second)
23✔
60

61
    // 4.- Finish Build Units Tasks
62
    const finishBuildUnitsTaskHandler = TASK_HANDLER[FINISH_BUILD_UNITS_TASK_TYPE].handler
23✔
63

64
    const finishBuildUnitsTasks = tasks.filter((task) => task.type === FINISH_BUILD_UNITS_TASK_TYPE)
23✔
65
    await processTasksInParallel(finishBuildUnitsTasks, finishBuildUnitsTaskHandler, second)
23✔
66

67
    // 5.- Start Build Units Tasks
68
    const startBuildUnitsTaskHandler = TASK_HANDLER[START_BUILD_UNITS_TASK_TYPE].handler
23✔
69

70
    const startBuildUnitsTasks = await taskRepository.getPendingTasksByType(
23✔
71
      universe._id,
72
      second,
73
      START_BUILD_UNITS_TASK_TYPE
74
    )
75
    await processTasksSequentially(startBuildUnitsTasks, startBuildUnitsTaskHandler, second)
23✔
76

77
    // update universe
78
    universe.lastProcessedTime = second
23✔
79
    await universe.save()
23✔
80
  }
81
}
82

83
export default processTasks
4✔
84

85
// TODO: add tests here
86
async function processTasksSequentially<Type extends TaskType>(
87
  tasks: ITaskDocument[],
88
  handler: TaskHandler<Type>,
89
  second: number
90
) {
91
  for (const task of tasks) {
69✔
92
    await setTaskAsProcessed(task, handler, second)
12✔
93
  }
94
}
95

96
async function processTasksInParallel<Type extends TaskType>(
97
  tasks: ITaskDocument[],
98
  handler: TaskHandler<Type>,
99
  second: number
100
) {
101
  return Promise.all(tasks.map((task) => setTaskAsProcessed(task, handler, second)))
46✔
102
}
103

104
async function setTaskAsProcessed<Type extends TaskType>(
105
  task: ITaskDocument,
106
  handler: TaskHandler<Type>,
107
  second: number
108
) {
109
  const startTime = new Date().getTime()
23✔
110
  try {
23✔
111
    await handler(task as ITaskTypeDocument<Type>, second)
23✔
112
    task.status = PROCESSED_TASK_STATUS
13✔
113
    task.history.push({ taskStatus: PROCESSED_TASK_STATUS, updatedAt: new Date().getTime() })
13✔
114
  } catch (error) {
115
    // TODO: create a task.error as an object
116
    // task.error.message
117
    // task.error.details
118
    // task.error.extraData
119

120
    task.errorDetails = (error as Error)?.message
10✔
121

122
    if (error?.constructor?.name === 'MongoServerError') {
10!
NEW
123
      const mongoError = error as MongoServerError
×
NEW
124
      task.errorDetails = mongoError.message
×
125
    }
126
    if (error instanceof GameEngineError) {
10✔
127
      task.errorDetails = error.message
10✔
128
    }
129

130
    task.status = ERROR_TASK_STATUS
10✔
131
    task.history.push({ taskStatus: ERROR_TASK_STATUS, updatedAt: new Date().getTime() })
10✔
132
  }
133

134
  task.isCancellable = false
23✔
135
  task.processedAt = second
23✔
136
  const endTime = new Date().getTime()
23✔
137
  task.processingDuration = endTime - startTime
23✔
138
  return task.save()
23✔
139
}
140

141
async function processResourceProduction(
142
  tasks: ITaskTypeDocument<TaskType>[],
143
  second: number
144
): Promise<IPlanetDocument[]> {
145
  const planets: {
146
    planet: IPlanetDocument
147
    owner: IPlayerDocument
148
  }[] = []
23✔
149

150
  // TODO: implement targetPlanet feature
151
  for (const task of tasks) {
23✔
152
    // calculate all player planet production
153
    if (isPlayerTaskData(task.data)) {
23✔
154
      const player = await playerRepository.findPlayerById(task.data.playerId)
17✔
155

156
      if (player) {
17✔
157
        const playerPlanets = player.planets.colonies
15✔
158

159
        playerPlanets.forEach((playerPlanet) => {
15✔
160
          const isAlreadyIncluded = planets.some(({ planet }) =>
15✔
161
            planet._id.equals(playerPlanet._id)
×
162
          )
163

164
          if (!isAlreadyIncluded) {
15✔
165
            planets.push({
15✔
166
              planet: playerPlanet,
167
              owner: player
168
            })
169
          }
170
        })
171
      }
172
    }
173
  }
174

175
  return Promise.all(
23✔
176
    planets.map(({ planet, owner }) => {
177
      const ownerResourceProductionBonus = computedBonus(owner.perks, 'RESOURCE_PRODUCTION_BONUS')
15✔
178

179
      planet.resources = calculateResourceProduction(
15✔
180
        second,
181
        planet.resources,
182
        planet.lastResourceProductionTime,
183
        planet.resourceQuality,
184
        ownerResourceProductionBonus
185
      )
186
      planet.lastResourceProductionTime = second
15✔
187

188
      return planet.save()
15✔
189
    })
190
  )
191
}
192

193
function isPlayerTaskData(
194
  taskData: TaskData<TaskType>
195
): taskData is
196
  | StartResearchTaskData
197
  | FinishResearchTaskData
198
  | StartBuildUnitsTaskData
199
  | FinishBuildUnitsTaskData {
200
  return 'playerId' in taskData
23✔
201
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc