gameplay: port timer phases and damage requests
Browse files- crates/urt-gameplay/src/bin/urt-client-timer.rs +44 -0
- crates/urt-gameplay/src/client_timer.rs +129 -0
- docs/FINDINGS.md +2 -0
- docs/PROVISIONAL_TODO.md +2 -0
- docs/RESEARCH_LEDGER.md +4 -0
- docs/REVERSE_ENGINEERING_TODO.md +2 -0
- docs/research/README.md +2 -0
- docs/research/RUST_CLIENT_TIMER_TICKS.md +5 -0
- docs/research/rust-client-timer-ticks.json +0 -0
- docs/research/rust-health-impulse.json +1 -1
- scripts/analyze_rust_client_timer_ticks.py +18 -0
- scripts/test_rust_client_timer_ticks.py +9 -0
- xtask/checks.tsv +20 -0
crates/urt-gameplay/src/bin/urt-client-timer.rs
CHANGED
|
@@ -29,6 +29,50 @@ fn main() {
|
|
| 29 |
input.stamp
|
| 30 |
);
|
| 31 |
}
|
|
|
|
| 32 |
_ => panic!("unknown timer policy"),
|
| 33 |
}
|
| 34 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
input.stamp
|
| 30 |
);
|
| 31 |
}
|
| 32 |
+
"tick" => println!("{}", tick(&w)),
|
| 33 |
_ => panic!("unknown timer policy"),
|
| 34 |
}
|
| 35 |
}
|
| 36 |
+
|
| 37 |
+
fn list(v: &[u32]) -> String {
|
| 38 |
+
format!(
|
| 39 |
+
"[{}]",
|
| 40 |
+
v.iter()
|
| 41 |
+
.map(|v| v.to_string())
|
| 42 |
+
.collect::<Vec<_>>()
|
| 43 |
+
.join(",")
|
| 44 |
+
)
|
| 45 |
+
}
|
| 46 |
+
fn damage_json(v: &[TimerDamage]) -> String {
|
| 47 |
+
v.iter().map(|r|format!(r#"{{"target":{},"inflictor":{},"attacker":{},"direction":{},"point":{},"amount":{},"flags":{},"means":{},"weapon":{}}}"#,r.target,r.inflictor,r.attacker,r.direction,r.point,r.amount,r.flags,r.means,r.weapon)).collect::<Vec<_>>().join(",")
|
| 48 |
+
}
|
| 49 |
+
fn loop_state(w: &[u32]) -> TimerLoopState {
|
| 50 |
+
TimerLoopState {
|
| 51 |
+
flags: w[0],
|
| 52 |
+
status: w[1],
|
| 53 |
+
rate: w[2],
|
| 54 |
+
phase: w[3],
|
| 55 |
+
timer: w[4],
|
| 56 |
+
residual: w[5],
|
| 57 |
+
}
|
| 58 |
+
}
|
| 59 |
+
fn loop_words(s: TimerLoopState) -> [u32; 6] {
|
| 60 |
+
[s.flags, s.status, s.rate, s.phase, s.timer, s.residual]
|
| 61 |
+
}
|
| 62 |
+
fn tick(w: &[u32]) -> String {
|
| 63 |
+
assert_eq!(w.len(), 8);
|
| 64 |
+
let mut s = loop_state(w);
|
| 65 |
+
let input = TimerLoopInput {
|
| 66 |
+
health: w[6],
|
| 67 |
+
weapon: w[7],
|
| 68 |
+
target: 2,
|
| 69 |
+
owner: 3,
|
| 70 |
+
};
|
| 71 |
+
let damage = timer_tick_loop(&mut s, input).unwrap();
|
| 72 |
+
format!(
|
| 73 |
+
r#"{{"damage":[{}],"state":{},"health":{}}}"#,
|
| 74 |
+
damage_json(&damage),
|
| 75 |
+
list(&loop_words(s)),
|
| 76 |
+
w[6]
|
| 77 |
+
)
|
| 78 |
+
}
|
crates/urt-gameplay/src/client_timer.rs
CHANGED
|
@@ -87,3 +87,132 @@ mod terminal_tests {
|
|
| 87 |
assert_eq!(s.entity_flag, 7);
|
| 88 |
}
|
| 89 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 87 |
assert_eq!(s.entity_flag, 7);
|
| 88 |
}
|
| 89 |
}
|
| 90 |
+
|
| 91 |
+
use crate::native_policy::Error;
|
| 92 |
+
pub const TIMER_DIVISORS: [i32; 6] = [1120403456, 9, 4, 3, 2, 1];
|
| 93 |
+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
| 94 |
+
pub struct TimerLoopState {
|
| 95 |
+
pub flags: u32,
|
| 96 |
+
pub status: u32,
|
| 97 |
+
pub rate: u32,
|
| 98 |
+
pub phase: u32,
|
| 99 |
+
pub timer: u32,
|
| 100 |
+
pub residual: u32,
|
| 101 |
+
}
|
| 102 |
+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
| 103 |
+
pub struct TimerLoopInput {
|
| 104 |
+
pub health: u32,
|
| 105 |
+
pub weapon: u32,
|
| 106 |
+
pub target: u32,
|
| 107 |
+
pub owner: u32,
|
| 108 |
+
}
|
| 109 |
+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
| 110 |
+
pub struct TimerDamage {
|
| 111 |
+
pub target: u32,
|
| 112 |
+
pub inflictor: u32,
|
| 113 |
+
pub attacker: u32,
|
| 114 |
+
pub direction: u32,
|
| 115 |
+
pub point: u32,
|
| 116 |
+
pub amount: u32,
|
| 117 |
+
pub flags: u32,
|
| 118 |
+
pub means: u32,
|
| 119 |
+
pub weapon: u32,
|
| 120 |
+
}
|
| 121 |
+
/// Original150810 loop subset with flag512 disabled. Damage effects are requests;
|
| 122 |
+
/// supplied health is deliberately unchanged. Rate0 aliases the preceding word.
|
| 123 |
+
pub fn timer_tick_loop(
|
| 124 |
+
state: &mut TimerLoopState,
|
| 125 |
+
input: TimerLoopInput,
|
| 126 |
+
) -> Result<Vec<TimerDamage>, Error> {
|
| 127 |
+
if state.rate > 5 {
|
| 128 |
+
return Err(Error::InvalidIndex);
|
| 129 |
+
}
|
| 130 |
+
if state.flags & 512 != 0 || state.residual as i32 > 10000 {
|
| 131 |
+
return Err(Error::InvalidInput);
|
| 132 |
+
}
|
| 133 |
+
let mut next = *state;
|
| 134 |
+
let mut damage = vec![];
|
| 135 |
+
while next.residual as i32 >= 100 {
|
| 136 |
+
next.phase =
|
| 137 |
+
((next.phase.wrapping_add(1) as i32) % TIMER_DIVISORS[next.rate as usize]) as u32;
|
| 138 |
+
next.residual = next.residual.wrapping_sub(100);
|
| 139 |
+
if next.flags & 256 != 0 && (input.health as i32) > 0 && next.phase == 0 {
|
| 140 |
+
damage.push(TimerDamage {
|
| 141 |
+
target: input.target,
|
| 142 |
+
inflictor: input.owner,
|
| 143 |
+
attacker: input.owner,
|
| 144 |
+
direction: 0,
|
| 145 |
+
point: 0,
|
| 146 |
+
amount: 1,
|
| 147 |
+
flags: 0,
|
| 148 |
+
means: 23,
|
| 149 |
+
weapon: input.weapon,
|
| 150 |
+
});
|
| 151 |
+
}
|
| 152 |
+
}
|
| 153 |
+
*state = next;
|
| 154 |
+
Ok(damage)
|
| 155 |
+
}
|
| 156 |
+
#[cfg(test)]
|
| 157 |
+
mod tick_tests {
|
| 158 |
+
use super::*;
|
| 159 |
+
fn input() -> TimerLoopInput {
|
| 160 |
+
TimerLoopInput {
|
| 161 |
+
health: 1,
|
| 162 |
+
weapon: 7,
|
| 163 |
+
target: 2,
|
| 164 |
+
owner: 3,
|
| 165 |
+
}
|
| 166 |
+
}
|
| 167 |
+
#[test]
|
| 168 |
+
fn phase_wrap_signed_remainder_alias_and_request_arguments() {
|
| 169 |
+
let mut s = TimerLoopState {
|
| 170 |
+
flags: 256,
|
| 171 |
+
status: 3,
|
| 172 |
+
rate: 0,
|
| 173 |
+
phase: 0,
|
| 174 |
+
timer: 0,
|
| 175 |
+
residual: 250,
|
| 176 |
+
};
|
| 177 |
+
assert!(timer_tick_loop(&mut s, input()).unwrap().is_empty());
|
| 178 |
+
assert_eq!(s.phase, 2);
|
| 179 |
+
assert_eq!(s.residual, 50);
|
| 180 |
+
s.rate = 5;
|
| 181 |
+
s.residual = 100;
|
| 182 |
+
s.phase = i32::MAX as u32;
|
| 183 |
+
let p = timer_tick_loop(&mut s, input()).unwrap();
|
| 184 |
+
assert_eq!(s.phase, 0);
|
| 185 |
+
assert_eq!(
|
| 186 |
+
p,
|
| 187 |
+
[TimerDamage {
|
| 188 |
+
target: 2,
|
| 189 |
+
inflictor: 3,
|
| 190 |
+
attacker: 3,
|
| 191 |
+
direction: 0,
|
| 192 |
+
point: 0,
|
| 193 |
+
amount: 1,
|
| 194 |
+
flags: 0,
|
| 195 |
+
means: 23,
|
| 196 |
+
weapon: 7
|
| 197 |
+
}]
|
| 198 |
+
);
|
| 199 |
+
}
|
| 200 |
+
#[test]
|
| 201 |
+
fn negative_residual_skips_and_unsupported_domains_are_atomic() {
|
| 202 |
+
let mut s = TimerLoopState {
|
| 203 |
+
flags: 256,
|
| 204 |
+
status: 3,
|
| 205 |
+
rate: 2,
|
| 206 |
+
phase: 0,
|
| 207 |
+
timer: 0,
|
| 208 |
+
residual: u32::MAX,
|
| 209 |
+
};
|
| 210 |
+
let old = s;
|
| 211 |
+
assert!(timer_tick_loop(&mut s, input()).unwrap().is_empty());
|
| 212 |
+
assert_eq!(s, old);
|
| 213 |
+
s.rate = 6;
|
| 214 |
+
let old = s;
|
| 215 |
+
assert!(timer_tick_loop(&mut s, input()).is_err());
|
| 216 |
+
assert_eq!(s, old);
|
| 217 |
+
}
|
| 218 |
+
}
|
docs/FINDINGS.md
CHANGED
|
@@ -1865,3 +1865,5 @@ RE-964: A144-case source contract executes disjoint150791..150810 and151085..151
|
|
| 1865 |
RE-965: Rust matches144 original terminal-fragment cases, preserving wrapping cooldown arithmetic before signed comparisons, strict equality behavior, unrelated flag bits and elapsed-total wrap. Separate pre-loop and post-loop APIs allow later composition in original order. Unit tests cover equal/expired deadlines and signed overflow; this contract does not execute the intervening timer loop or native scheduling. [Evidence](research/RUST_CLIENT_TIMER_TERMINAL.md).
|
| 1866 |
|
| 1867 |
RE-966: A288-case source loop contract covers signed residual thresholds, wrapping phase increments and signed remainder with rates0/1/2/5. Rate0 reads preceding word1120403456 instead of a zero divisor. Flag256 plus positive supplied health and phase0 request damage1, means23 and caller weapon/owner pointers. Damage effects remain captured and flag512 is disabled in this stage; health mutation and other branches remain open. [Evidence](research/QVM_CLIENT_TIMER_TICKS.md).
|
|
|
|
|
|
|
|
|
| 1865 |
RE-965: Rust matches144 original terminal-fragment cases, preserving wrapping cooldown arithmetic before signed comparisons, strict equality behavior, unrelated flag bits and elapsed-total wrap. Separate pre-loop and post-loop APIs allow later composition in original order. Unit tests cover equal/expired deadlines and signed overflow; this contract does not execute the intervening timer loop or native scheduling. [Evidence](research/RUST_CLIENT_TIMER_TERMINAL.md).
|
| 1866 |
|
| 1867 |
RE-966: A288-case source loop contract covers signed residual thresholds, wrapping phase increments and signed remainder with rates0/1/2/5. Rate0 reads preceding word1120403456 instead of a zero divisor. Flag256 plus positive supplied health and phase0 request damage1, means23 and caller weapon/owner pointers. Damage effects remain captured and flag512 is disabled in this stage; health mutation and other branches remain open. [Evidence](research/QVM_CLIENT_TIMER_TICKS.md).
|
| 1868 |
+
|
| 1869 |
+
RE-967: Rust matches288 original tick-loop cases with signed residual/remainder and wrapping phase behavior. Rate0 retains the preceding-word divisor1120403456. Typed damage requests retain all source arguments without mutating supplied health. Unit tests cover alias behavior, signed wrap, exact request ABI and atomic invalid-rate rejection. Flag512 is deliberately outside this first loop subset; the residual budget bounds execution. [Evidence](research/RUST_CLIENT_TIMER_TICKS.md).
|
docs/PROVISIONAL_TODO.md
CHANGED
|
@@ -1917,3 +1917,5 @@ RE-954–963 completed add/remove wrappers, resolved duration export, full-capac
|
|
| 1917 |
- [x] RE-965 Rust client timer deadlines and terminal accumulation ([evidence](research/RUST_CLIENT_TIMER_TERMINAL.md)).
|
| 1918 |
|
| 1919 |
- [x] RE-966 Original100ms timer phase loop and damage-request ABI ([evidence](research/QVM_CLIENT_TIMER_TICKS.md)).
|
|
|
|
|
|
|
|
|
| 1917 |
- [x] RE-965 Rust client timer deadlines and terminal accumulation ([evidence](research/RUST_CLIENT_TIMER_TERMINAL.md)).
|
| 1918 |
|
| 1919 |
- [x] RE-966 Original100ms timer phase loop and damage-request ABI ([evidence](research/QVM_CLIENT_TIMER_TICKS.md)).
|
| 1920 |
+
|
| 1921 |
+
- [x] RE-967 Rust100ms phase loop and captured damage requests ([evidence](research/RUST_CLIENT_TIMER_TICKS.md)).
|
docs/RESEARCH_LEDGER.md
CHANGED
|
@@ -2535,3 +2535,7 @@ Rust matches144 original terminal-fragment cases, preserving wrapping cooldown a
|
|
| 2535 |
## 2026-10-28 — RE-966 Original100ms timer phase loop and damage-request ABI
|
| 2536 |
|
| 2537 |
A288-case source loop contract covers signed residual thresholds, wrapping phase increments and signed remainder with rates0/1/2/5. Rate0 reads preceding word1120403456 instead of a zero divisor. Flag256 plus positive supplied health and phase0 request damage1, means23 and caller weapon/owner pointers. Damage effects remain captured and flag512 is disabled in this stage; health mutation and other branches remain open. Focused `cargo xtask test-group qvm-client-timer-ticks` passes with deterministic report regeneration, relevant regressions and storage/documentation/whitespace checks. Full suite deferred to the tenth-commit boundary. Original assets unchanged; native IO effects remain captured.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2535 |
## 2026-10-28 — RE-966 Original100ms timer phase loop and damage-request ABI
|
| 2536 |
|
| 2537 |
A288-case source loop contract covers signed residual thresholds, wrapping phase increments and signed remainder with rates0/1/2/5. Rate0 reads preceding word1120403456 instead of a zero divisor. Flag256 plus positive supplied health and phase0 request damage1, means23 and caller weapon/owner pointers. Damage effects remain captured and flag512 is disabled in this stage; health mutation and other branches remain open. Focused `cargo xtask test-group qvm-client-timer-ticks` passes with deterministic report regeneration, relevant regressions and storage/documentation/whitespace checks. Full suite deferred to the tenth-commit boundary. Original assets unchanged; native IO effects remain captured.
|
| 2538 |
+
|
| 2539 |
+
## 2026-10-28 — RE-967 Rust100ms phase loop and captured damage requests
|
| 2540 |
+
|
| 2541 |
+
Rust matches288 original tick-loop cases with signed residual/remainder and wrapping phase behavior. Rate0 retains the preceding-word divisor1120403456. Typed damage requests retain all source arguments without mutating supplied health. Unit tests cover alias behavior, signed wrap, exact request ABI and atomic invalid-rate rejection. Flag512 is deliberately outside this first loop subset; the residual budget bounds execution. Focused `cargo xtask test-group rust-client-timer-ticks` passes with deterministic report regeneration, relevant regressions and storage/documentation/whitespace checks. Full suite deferred to the tenth-commit boundary. Original assets unchanged; native IO effects remain captured.
|
docs/REVERSE_ENGINEERING_TODO.md
CHANGED
|
@@ -1954,3 +1954,5 @@ RE-954–963 recover bounded command wrappers, resolved duration export, full-ca
|
|
| 1954 |
- [x] RE-965 Rust client timer deadlines and terminal accumulation ([evidence](research/RUST_CLIENT_TIMER_TERMINAL.md)).
|
| 1955 |
|
| 1956 |
- [x] RE-966 Original100ms timer phase loop and damage-request ABI ([evidence](research/QVM_CLIENT_TIMER_TICKS.md)).
|
|
|
|
|
|
|
|
|
| 1954 |
- [x] RE-965 Rust client timer deadlines and terminal accumulation ([evidence](research/RUST_CLIENT_TIMER_TERMINAL.md)).
|
| 1955 |
|
| 1956 |
- [x] RE-966 Original100ms timer phase loop and damage-request ABI ([evidence](research/QVM_CLIENT_TIMER_TICKS.md)).
|
| 1957 |
+
|
| 1958 |
+
- [x] RE-967 Rust100ms phase loop and captured damage requests ([evidence](research/RUST_CLIENT_TIMER_TICKS.md)).
|
docs/research/README.md
CHANGED
|
@@ -1489,3 +1489,5 @@ The extension collector adds five focused tests for native tail calls, command-r
|
|
| 1489 |
- [RE-965: Rust client timer deadlines and terminal accumulation](RUST_CLIENT_TIMER_TERMINAL.md).
|
| 1490 |
|
| 1491 |
- [RE-966: Original100ms timer phase loop and damage-request ABI](QVM_CLIENT_TIMER_TICKS.md).
|
|
|
|
|
|
|
|
|
| 1489 |
- [RE-965: Rust client timer deadlines and terminal accumulation](RUST_CLIENT_TIMER_TERMINAL.md).
|
| 1490 |
|
| 1491 |
- [RE-966: Original100ms timer phase loop and damage-request ABI](QVM_CLIENT_TIMER_TICKS.md).
|
| 1492 |
+
|
| 1493 |
+
- [RE-967: Rust100ms phase loop and captured damage requests](RUST_CLIENT_TIMER_TICKS.md).
|
docs/research/RUST_CLIENT_TIMER_TICKS.md
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Rust100ms phase loop and captured damage requests
|
| 2 |
+
|
| 3 |
+
RE-967. Focused validation: `cargo xtask test-group rust-client-timer-ticks`. [Machine report](rust-client-timer-ticks.json).
|
| 4 |
+
|
| 5 |
+
Rust matches288 original tick-loop cases with signed residual/remainder and wrapping phase behavior. Rate0 retains the preceding-word divisor1120403456. Typed damage requests retain all source arguments without mutating supplied health. Unit tests cover alias behavior, signed wrap, exact request ABI and atomic invalid-rate rejection. Flag512 is deliberately outside this first loop subset; the residual budget bounds execution.
|
docs/research/rust-client-timer-ticks.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
docs/research/rust-health-impulse.json
CHANGED
|
@@ -2985,7 +2985,7 @@
|
|
| 2985 |
"exit_code": 2
|
| 2986 |
}
|
| 2987 |
],
|
| 2988 |
-
"rust_unit_tests":
|
| 2989 |
"source_report": "docs/research/qvm-health-impulse.json",
|
| 2990 |
"source_report_sha256": "625fd8064004ea6dbdf398d51d0af844d9c635ff04c0a0790886dddb6ab81e71"
|
| 2991 |
}
|
|
|
|
| 2985 |
"exit_code": 2
|
| 2986 |
}
|
| 2987 |
],
|
| 2988 |
+
"rust_unit_tests": 224,
|
| 2989 |
"source_report": "docs/research/qvm-health-impulse.json",
|
| 2990 |
"source_report_sha256": "625fd8064004ea6dbdf398d51d0af844d9c635ff04c0a0790886dddb6ab81e71"
|
| 2991 |
}
|
scripts/analyze_rust_client_timer_ticks.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Compare recovered Rust policy with original QVM fixtures."""
|
| 2 |
+
import hashlib,json,os,subprocess
|
| 3 |
+
from pathlib import Path
|
| 4 |
+
from analyze_qvm import write_json
|
| 5 |
+
from rust_lifecycle_support import result
|
| 6 |
+
|
| 7 |
+
def main():
|
| 8 |
+
subprocess.run(['cargo','build','--offline','--package','urt-gameplay','--bin','urt-client-timer'],check=True,capture_output=True)
|
| 9 |
+
binary=Path(os.environ.get('CARGO_TARGET_DIR','target'))/'debug'/'urt-client-timer'
|
| 10 |
+
path=Path('docs/research/qvm-client-timer-ticks.json');data=path.read_bytes();probes=[]
|
| 11 |
+
for p in json.loads(data)['probes']:
|
| 12 |
+
probes.append(dict(source={k:p[k] for k in ['damage', 'state', 'health']},rust=result(binary,'tick',encode(p['input']))))
|
| 13 |
+
write_json(Path('docs/research/rust-client-timer-ticks.json'),dict(source_report=str(path),source_report_sha256=hashlib.sha256(data).hexdigest(),probes=probes,limits='Finite source/Rust contract parity; native time/file/network replies remain supplied or captured.'))
|
| 14 |
+
|
| 15 |
+
def encode(a):
|
| 16 |
+
from analyze_qvm_acceleration import word
|
| 17 |
+
return [a['flags'],a['status'],a['rate'],a['phase'],word(a['timer']),a['residual'],a['health'],a['weapon']]
|
| 18 |
+
if __name__=='__main__':main()
|
scripts/test_rust_client_timer_ticks.py
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import hashlib,json,unittest
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
class PortTests(unittest.TestCase):
|
| 4 |
+
def test_original_parity(self):
|
| 5 |
+
r=json.loads(Path('docs/research/rust-client-timer-ticks.json').read_text());self.assertGreaterEqual(len(r['probes']),12)
|
| 6 |
+
for p in r['probes']:self.assertEqual(p['source'],p['rust'])
|
| 7 |
+
def test_identity(self):
|
| 8 |
+
r=json.loads(Path('docs/research/rust-client-timer-ticks.json').read_text());self.assertEqual(hashlib.sha256(Path(r['source_report']).read_bytes()).hexdigest(),r['source_report_sha256'])
|
| 9 |
+
if __name__=='__main__':unittest.main()
|
xtask/checks.tsv
CHANGED
|
@@ -3446,3 +3446,23 @@ report scripts/analyze_qvm_client_timer_ticks.py docs/research/qvm-client-timer-
|
|
| 3446 |
edge docs/research/qvm-client-timer-ticks.json scripts/test_qvm_client_timer_ticks.py
|
| 3447 |
group qvm-client-timer-ticks scripts/analyze_qvm_client_timer_ticks.py
|
| 3448 |
edge scripts/analyze_qvm_client_timer_ticks.py scripts/analyze_qvm_resumer_audit.py
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3446 |
edge docs/research/qvm-client-timer-ticks.json scripts/test_qvm_client_timer_ticks.py
|
| 3447 |
group qvm-client-timer-ticks scripts/analyze_qvm_client_timer_ticks.py
|
| 3448 |
edge scripts/analyze_qvm_client_timer_ticks.py scripts/analyze_qvm_resumer_audit.py
|
| 3449 |
+
report scripts/analyze_rust_client_timer_ticks.py docs/research/rust-client-timer-ticks.json
|
| 3450 |
+
edge docs/research/rust-client-timer-ticks.json scripts/test_rust_client_timer_ticks.py
|
| 3451 |
+
group rust-client-timer-ticks scripts/analyze_rust_client_timer_ticks.py
|
| 3452 |
+
edge scripts/analyze_rust_client_timer_ticks.py scripts/analyze_qvm_resumer_audit.py
|
| 3453 |
+
edge Cargo.toml scripts/analyze_rust_client_timer_ticks.py
|
| 3454 |
+
edge Cargo.lock scripts/analyze_rust_client_timer_ticks.py
|
| 3455 |
+
edge crates/urt-gameplay/Cargo.toml scripts/analyze_rust_client_timer_ticks.py
|
| 3456 |
+
edge crates/urt-gameplay/src/lib.rs scripts/analyze_rust_client_timer_ticks.py
|
| 3457 |
+
edge crates/urt-gameplay/src/filter_loading.rs scripts/analyze_rust_client_timer_ticks.py
|
| 3458 |
+
edge crates/urt-gameplay/src/filter_lifecycle.rs scripts/analyze_rust_client_timer_ticks.py
|
| 3459 |
+
edge crates/urt-gameplay/src/native_policy.rs scripts/analyze_rust_client_timer_ticks.py
|
| 3460 |
+
edge crates/urt-gameplay/src/bin/urt-filter-loading.rs scripts/analyze_rust_client_timer_ticks.py
|
| 3461 |
+
edge crates/urt-gameplay/src/qvm_format.rs scripts/analyze_rust_client_timer_ticks.py
|
| 3462 |
+
edge docs/research/qvm-client-timer-ticks.json scripts/analyze_rust_client_timer_ticks.py
|
| 3463 |
+
group rust-client-timer-ticks scripts/analyze_rust_health_impulse.py
|
| 3464 |
+
group gameplay scripts/analyze_rust_client_timer_ticks.py
|
| 3465 |
+
edge crates/urt-gameplay/src/filter_commands.rs scripts/analyze_rust_client_timer_ticks.py
|
| 3466 |
+
edge crates/urt-gameplay/src/bin/urt-filter-commands.rs scripts/analyze_rust_client_timer_ticks.py
|
| 3467 |
+
edge crates/urt-gameplay/src/client_timer.rs scripts/analyze_rust_client_timer_ticks.py
|
| 3468 |
+
edge crates/urt-gameplay/src/bin/urt-client-timer.rs scripts/analyze_rust_client_timer_ticks.py
|