6 n__clock__sync_8h
gullradriel edited this page 2026-10-09 00:55:18 +02:00

include/nilorea/n_clock_sync.h

Clock synchronization estimator for networked games. More...

Structures

Name
struct N_CLOCK_SYNC
clock synchronization estimator

Detailed Description

Clock synchronization estimator for networked games.

Author: Castagnier Mickael

Version: 1.1

Date: 19/07/2026

Estimates the time offset between a local clock and a remote clock using periodic sync request/response pairs. The offset adopted is the sample with the lowest RTT (NTP-style, smallest one-way uncertainty); absurd-RTT responses are rejected; consumers read the offset through n_clock_sync_server_time, which slews across estimate changes instead of stepping. Request cadence bursts until the estimator is warm.

Usage:

N_CLOCK_SYNC *cs = n_clock_sync_new();

// Periodically:
if (n_clock_sync_should_send(cs, local_now)) {
    n_clock_sync_mark_sent(cs, local_now);
    send_sync_request(local_now);  // include local_now in request
}

// On response:
n_clock_sync_process_response(cs, client_send_time, server_time, local_now);

// Convert local time to estimated server time:
double srv_time = n_clock_sync_server_time(cs, local_now);

n_clock_sync_delete(&cs);

Source code

/*
 * Nilorea Library
 * Copyright (C) 2005-2026 Castagnier Mickael
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * permissions and limitations under the License.
 *
 * SPDX-License-Identifier: Apache-2.0
 */


#ifndef __N_CLOCK_SYNC_HEADER
#define __N_CLOCK_SYNC_HEADER

#ifdef __cplusplus
extern "C" {
#endif


#include "n_common.h"

#ifndef N_CLOCK_SYNC_SAMPLE_COUNT
#define N_CLOCK_SYNC_SAMPLE_COUNT 11
#endif

#ifndef N_CLOCK_SYNC_INTERVAL
#define N_CLOCK_SYNC_INTERVAL 3.0
#endif

#ifndef N_CLOCK_SYNC_BURST_INTERVAL
#define N_CLOCK_SYNC_BURST_INTERVAL 0.5
#endif

#ifndef N_CLOCK_SYNC_BURST_SAMPLES
#define N_CLOCK_SYNC_BURST_SAMPLES 5
#endif

#ifndef N_CLOCK_SYNC_MAX_RTT
#define N_CLOCK_SYNC_MAX_RTT 10.0
#endif

#ifndef N_CLOCK_SYNC_SLEW_SECONDS
#define N_CLOCK_SYNC_SLEW_SECONDS 1.0
#endif

typedef struct N_CLOCK_SYNC {
    double offset_samples[N_CLOCK_SYNC_SAMPLE_COUNT];
    double rtt_samples[N_CLOCK_SYNC_SAMPLE_COUNT];
    int sample_index;
    int sample_count;

    double estimated_offset;
    double estimated_rtt;

    double last_sync_time;

    int synthetic;

    double offset_prev;
    double offset_change_time;

} N_CLOCK_SYNC;

N_CLOCK_SYNC* n_clock_sync_new(void);

void n_clock_sync_delete(N_CLOCK_SYNC** cs);

int n_clock_sync_process_response(N_CLOCK_SYNC* cs, double client_send_time, double server_time, double local_now);

void n_clock_sync_seed(N_CLOCK_SYNC* cs, double offset, double rtt);

double n_clock_sync_server_time(const N_CLOCK_SYNC* cs, double local_now);

int n_clock_sync_should_send(const N_CLOCK_SYNC* cs, double local_now);

void n_clock_sync_mark_sent(N_CLOCK_SYNC* cs, double local_now);


#ifdef __cplusplus
}
#endif
#endif /* __N_CLOCK_SYNC_HEADER */