The Turret API
EVE Frontier turrets are programmable defense systems attached to player structures. Unlike most smart contracts where you decide when to call them, turret targeting code is called by the game engine whenever a potential target enters range. Your job is to write the targeting logic -- the game handles everything else.
The Function Signature
Every turret targeting module must expose a function with this exact signature:
public fun get_target_priority_list(
turret: &Turret,
owner_character: &Character,
target_candidate_list: vector<u8>,
receipt: OnlineReceipt,
): vector<u8>The game engine calls this function with four arguments. You cannot change the parameter types or add extra parameters -- the interface is fixed.
Parameter 1: turret (&Turret)
An immutable reference to the turret object. Contains the turret's on-chain state (ID, configuration, etc.). You use this primarily for identity verification:
assert!(receipt.turret_id() == object::id(turret), 0);Parameter 2: owner_character (&Character)
The character who owns the turret. You can read properties from this:
let owner_tribe = owner_character.tribe(); // u32 tribe ID
let owner_char_id = owner_character.key().item_id(); // u64 character IDThis is how targeting modes decide which targets are "friendly" -- they compare the candidate's tribe with the owner's tribe.
Parameter 3: target_candidate_list (vector<u8>)
A BCS-encoded byte array containing all potential targets in range. You must unpack it:
let candidates = turret::unpack_candidate_list(target_candidate_list);This returns a vector. Each candidate has these accessor functions:
| Accessor | Type | Description |
item_id() | u64 | Unique item ID of the target |
character_id() | u32 | Character ID of the target's pilot |
character_tribe() | u32 | Tribe ID of the target |
is_aggressor() | bool | Whether the target has recently attacked |
priority_weight() | u64 | Default priority weight from the game engine |
Parameter 4: receipt (OnlineReceipt)
The OnlineReceipt is a hot potato -- a value without the drop ability. You must consume it by calling turret::destroy_online_receipt at the end of your function. If you forget, the code will not compile.
turret::destroy_online_receipt(receipt, AggressionAuth {});The second argument to destroy_online_receipt is a typed witness (like XAuth in the storage extension). It proves which targeting module is handling the receipt.
The Hot Potato Pattern
The OnlineReceipt pattern ensures two things:
OnlineReceipt goes out of scope without being destroyed.OnlineReceipt for turrets that are currently online. By requiring the receipt, the function signature guarantees it cannot be called for offline turrets.// This struct does NOT have drop
// public struct OnlineReceipt has key {
// id: UID,
// turret_id: ID,
// }
// So this would fail to compile:
public fun bad_targeting(receipt: OnlineReceipt): vector<u8> {
// ERROR: receipt is not consumed!
vector::empty()
}
// You must destroy it:
public fun good_targeting(receipt: OnlineReceipt): vector<u8> {
let result = vector::empty();
turret::destroy_online_receipt(receipt, MyAuth {});
result
}The Auth Witness
Each targeting module defines its own auth witness:
public struct AggressionAuth has drop {}This serves the same purpose as XAuth in the storage extension -- it identifies which module is handling the turret. The SSU/turret owner authorizes a specific witness type, and only that module can produce it.
Return Value
The function returns vector -- a BCS-encoded list of targets with priorities:
let mut return_list = vector::empty<turret::ReturnTargetPriorityList>();
// Add targets with priority weights
return_list.push_back(turret::new_return_target_priority_list(
candidate.item_id(),
candidate.priority_weight() + 10000,
));
// Encode and return
let result = bcs::to_bytes(&return_list);Each entry in the return list contains:
- item_id: Which target to shoot (must be from the candidate list)
- priority_weight: Higher weight = higher priority = shoot first
Targets not included in the return list are ignored by the turret.
Putting It Together: Minimal Targeting Module
Here is the absolute minimum targeting module that shoots everyone:
module my_turret::shoot_everyone;
use sui::bcs;
use world::character::Character;
use world::turret::{Self, Turret, OnlineReceipt};
public struct ShootAllAuth has drop {}
public fun get_target_priority_list(
turret: &Turret,
_owner: &Character,
target_candidate_list: vector<u8>,
receipt: OnlineReceipt,
): vector<u8> {
assert!(receipt.turret_id() == object::id(turret), 0);
let candidates = turret::unpack_candidate_list(target_candidate_list);
let mut targets = vector::empty<turret::ReturnTargetPriorityList>();
let mut i = 0;
while (i < candidates.length()) {
let c = candidates.borrow(i);
targets.push_back(
turret::new_return_target_priority_list(c.item_id(), c.priority_weight()),
);
i = i + 1;
};
let result = bcs::to_bytes(&targets);
turret::destroy_online_receipt(receipt, ShootAllAuth {});
result
}This module includes every candidate in the return list with their default priority weight. No filtering, no tribe checks, no aggression checks.
Key Takeaways
- Turret targeting modules implement
get_target_priority_listwith a fixed 4-parameter signature. - The game engine calls this function -- you do not call it yourself.
target_candidate_listis BCS-encoded and must be unpacked withturret::unpack_candidate_list.OnlineReceiptis a hot potato that must be destroyed withturret::destroy_online_receiptand a typed auth witness.- The return value is a BCS-encoded list of
(item_id, priority_weight)pairs. Higher weight = higher priority. - Targets omitted from the return list are not fired upon.
Sign in to track your progress.