---
description: Creep Module - 生产 Creep 管理模块
---

# Spawn Module

在实现🤖️ Creep 模块之后，还需要处理该模块对外依赖的`生新的Creep`模块。

该对外依赖模块可以通过一个非常简单的优先队列实现，即每 tick 轮询所有房间，构造队列放置期望生产的 Creep，按照优先级别以及能量是否足够来完成生产。

### 📃  具体实现

```typescript
/**
 * Creep 生产模块
 */

function calculateBodyCost(bodies: BodyPartConstant[]) {
    let cost = 0
    for ( const body of bodies )
        cost += BODYPART_COST[body]
    return cost
}

type RequestCreepType = {
    callback: (name: string) => void, 
    cost: number, 
    body: BodyPartConstant[], 
    requestTick: number, 
    memory?: CreepMemory, 
    workPos?: RoomPosition
}

class CreepSpawnModule {
    #repo: { [roomName: string]: { [priority: number]: RequestCreepType[] } } = {}

    request(roomName: string, callback: (name: string) => void, body: BodyPartConstant[], priority: number, memory?: CreepMemory, workPos?: RoomPosition): void {
        if ( !(roomName in this.#repo) ) this.#repo[roomName] = {}
        if ( !(priority in this.#repo[roomName]) ) this.#repo[roomName][priority] = []
        this.#repo[roomName][priority].push({ callback, cost: calculateBodyCost(body), body, requestTick: Game.time, memory, workPos })
    }

    constructor() {
        // 轮询是否本 tick 生产新的 Creep
        A.timer.add(Game.time + 1, () => {
            for (const roomName in this.#repo) {
                // 每 tick 只检查一次
                const spawns = Game.rooms[roomName].find<FIND_MY_STRUCTURES, StructureSpawn>(FIND_MY_STRUCTURES, {filter: {structureType: STRUCTURE_SPAWN}})
                const availableSpawns = _.filter(spawns, s => !s.spawning )
                if ( availableSpawns.length === 0 ) continue

                // 按照优先级别顺序
                const priorities = _.sortBy(Object.keys(this.#repo[roomName]))
                let flag = false
                for (const priority of priorities) {
                    // 最高响应比优先调度算法
                    // 这里等待 tick 乘以的系数应当最好为每秒本房间
                    // energy 的产量
                    const orders = _.sortBy(this.#repo[roomName][priority], (element: RequestCreepType) => -((Game.time - element.requestTick) * 50.0 + element.cost) / element.cost)
                    for (const order of orders) {
                        // 检查是否为特定 Spawn
                        let spawn: StructureSpawn = null
                        if ( order.workPos && _.any(spawns, s => s.pos.getRangeTo(order.workPos) <= 1 ) ) {
                            spawn = _.select(spawns, s => s.pos.getRangeTo(order.workPos) <= 1)[0]
                            if ( !_.any(availableSpawns, s => s.id === spawn.id) ) continue
                        } else
                            spawn = availableSpawns[0]
                        
                        // 无论能量够不够, 都不再往后检查
                        flag = true
                        if ( Game.rooms[roomName].energyAvailable >= order.cost ) {
                            let name = null
                            while ( !name || name in Game.creeps )
                                name = `${roomName}-${generate_random_hex(4)}`
                            assertWithMsg(spawn.spawnCreep(order.body, name, {
                                memory: order.memory, 
                                directions: (order.workPos && spawn.pos.getRangeTo(order.workPos) <= 1)? [ spawn.pos.getDirectionTo(order.workPos) ] : []
                            }) === OK, `生产 Creep [${order.body}, ${roomName}] 时, 选定的 Spawn [${spawn.id}] 无法成功生产 Creep`)
                            A.timer.add(Game.time + 1, (name, callback) => {
                                if ( name in Game.creeps ) {
                                    callback(name)
                                    return A.timer.STOP
                                }
                            }, [ name, order.callback ], CREEP_SPAWN_TIME)
                        }
                    }
                    if ( flag ) break
                }
            }
        }, [], 1)
    }
}
```

{% content-ref url="spawn-module" %}
[spawn-module](spawn-module)
{% endcontent-ref %}
