package vendor_ggpo foreign import lib "GGPO.lib" import c "core:c/libc" Session :: distinct rawptr MAX_PLAYERS :: 4 MAX_PREDICTION_FRAMES :: 8 MAX_SPECTATORS :: 32 SPECTATOR_INPUT_INTERVAL :: 4 PlayerHandle :: distinct c.int PlayerType :: enum c.int { LOCAL, REMOTE, SPECTATOR, } /* * The Player structure used to describe players in add_player * * size: Should be set to the size_of(Player) * * type: One of the PlayerType values describing how inputs should be handled * Local players must have their inputs updated every frame via * add_local_inputs. Remote players values will come over the * network. * * player_num: The player number. Should be between 1 and the number of players * In the game (e.g. in a 2 player game, either 1 or 2). * * If type == PLAYERTYPE_REMOTE: * * remote.ip_address: The ip address of the ggpo session which will host this * player. * * remote.port: The port where udp packets should be sent to reach this player. * All the local inputs for this session will be sent to this player at * ip_address:port. * */ Player :: struct { size: c.int, type: PlayerType, player_num: c.int, using u: struct #raw_union { local: struct {}, remote: struct { ip_address: [32]byte, port: u16, }, }, } LocalEndpoint :: struct { player_num: c.int, } ErrorCode :: enum c.int { OK = 0, SUCCESS = 0, GENERAL_FAILURE = -1, INVALID_SESSION = 1, INVALID_PLAYER_HANDLE = 2, PLAYER_OUT_OF_RANGE = 3, PREDICTION_THRESHOLD = 4, UNSUPPORTED = 5, NOT_SYNCHRONIZED = 6, IN_ROLLBACK = 7, INPUT_DROPPED = 8, PLAYER_DISCONNECTED = 9, TOO_MANY_SPECTATORS = 10, INVALID_REQUEST = 11, } INVALID_HANDLE :: PlayerHandle(-1) /* * The EventCode enumeration describes what type of event just happened. * * CONNECTED_TO_PEER - Handshake with the game running on the * other side of the network has been completed. * * SYNCHRONIZING_WITH_PEER - Beginning the synchronization * process with the client on the other end of the networking. The count * and total fields in the u.synchronizing struct of the Event * object indicate progress. * * SYNCHRONIZED_WITH_PEER - The synchronziation with this * peer has finished. * * RUNNING - All the clients have synchronized. You may begin * sending inputs with synchronize_inputs. * * DISCONNECTED_FROM_PEER - The network connection on * the other end of the network has closed. * * TIMESYNC - The time synchronziation code has determined * that this client is too far ahead of the other one and should slow * down to ensure fairness. The u.timesync.frames_ahead parameter in * the Event object indicates how many frames the client is. * */ EventCode :: enum c.int { CONNECTED_TO_PEER = 1000, SYNCHRONIZING_WITH_PEER = 1001, SYNCHRONIZED_WITH_PEER = 1002, RUNNING = 1003, DISCONNECTED_FROM_PEER = 1004, TIMESYNC = 1005, CONNECTION_INTERRUPTED = 1006, CONNECTION_RESUMED = 1007, } /* * The Event structure contains an asynchronous event notification sent * by the on_event callback. See EventCode, above, for a detailed * explanation of each event. */ Event :: struct { code: EventCode, using u: struct #raw_union { connected: struct { player: PlayerHandle, }, synchronizing: struct { player: PlayerHandle, count: c.int, total: c.int, }, synchronized: struct { player: PlayerHandle, }, disconnected: struct { player: PlayerHandle, }, timesync: struct { frames_ahead: c.int, }, connection_interrupted: struct { player: PlayerHandle, disconnect_timeout: c.int, }, connection_resumed: struct { player: PlayerHandle, }, }, } /* * The SessionCallbacks structure contains the callback functions that * your application must implement. GGPO.net will periodically call these * functions during the game. All callback functions must be implemented. */ SessionCallbacks :: struct { /* * begin_game callback - This callback has been deprecated. You must * implement it, but should ignore the 'game' parameter. */ begin_game: proc "c" (game: cstring) -> bool, /* * save_game_state - The client should allocate a buffer, copy the * entire contents of the current game state into it, and copy the * length into the len parameter. Optionally, the client can compute * a checksum of the data and store it in the checksum argument. */ save_game_state: proc "c" (buffer: ^[^]byte, len: ^c.int, checksum: ^c.int, frame: c.int) -> bool, /* * load_game_state - GGPO.net will call this function at the beginning * of a rollback. The buffer and len parameters contain a previously * saved state returned from the save_game_state function. The client * should make the current game state match the state contained in the * buffer. */ load_game_state: proc "c" (buffer: [^]byte, len: c.int) -> bool, /* * log_game_state - Used in diagnostic testing. The client should use * the log function to write the contents of the specified save * state in a human readible form. */ log_game_state: proc "c" (filename: cstring, buffer: [^]byte, len: c.int) -> bool, /* * free_buffer - Frees a game state allocated in save_game_state. You * should deallocate the memory contained in the buffer. */ free_buffer: proc "c" (buffer: rawptr), /* * advance_frame - Called during a rollback. You should advance your game * state by exactly one frame. Before each frame, call synchronize_input * to retrieve the inputs you should use for that frame. After each frame, * you should call advance_frame to notify GGPO.net that you're * finished. * * The flags parameter is reserved. It can safely be ignored at this time. */ advance_frame: proc "c" (flags: c.int) -> bool, /* * on_event - Notification that something has happened. See the EventCode * structure above for more information. */ on_event: proc "c" (info: ^Event) -> bool, } /* * The NetworkStats function contains some statistics about the current * session. * * network.send_queue_len - The length of the queue containing UDP packets * which have not yet been acknowledged by the end client. The length of * the send queue is a rough indication of the quality of the connection. * The longer the send queue, the higher the round-trip time between the * clients. The send queue will also be longer than usual during high * packet loss situations. * * network.recv_queue_len - The number of inputs currently buffered by the * GGPO.net network layer which have yet to be validated. The length of * the prediction queue is roughly equal to the current frame number * minus the frame number of the last packet in the remote queue. * * network.ping - The roundtrip packet transmission time as calcuated * by GGPO.net. This will be roughly equal to the actual round trip * packet transmission time + 2 the interval at which you call idle * or advance_frame. * * network.kbps_sent - The estimated bandwidth used between the two * clients, in kilobits per second. * * timesync.local_frames_behind - The number of frames GGPO.net calculates * that the local client is behind the remote client at this instant in * time. For example, if at this instant the current game client is running * frame 1002 and the remote game client is running frame 1009, this value * will mostly likely roughly equal 7. * * timesync.remote_frames_behind - The same as local_frames_behind, but * calculated from the perspective of the remote player. * */ NetworkStats :: struct { network: struct { send_queue_len: c.int, recv_queue_len: c.int, ping: c.int, kbps_sent: c.int, }, timesync: struct { local_frames_behind: c.int, remote_frames_behind: c.int, }, } @(default_calling_convention="c") @(link_prefix="ggpo_") foreign lib { /* * start_session -- * * Used to being a new GGPO.net session. The ggpo object returned by start_session * uniquely identifies the state for this session and should be passed to all other * functions. * * session - An out parameter to the new ggpo session object. * * cb - A SessionCallbacks structure which contains the callbacks you implement * to help GGPO.net synchronize the two games. You must implement all functions in * cb, even if they do nothing but 'return true'; * * game - The name of the game. This is used internally for GGPO for logging purposes only. * * num_players - The number of players which will be in this game. The number of players * per session is fixed. If you need to change the number of players or any player * disconnects, you must start a new session. * * input_size - The size of the game inputs which will be passsed to add_local_input. * * local_port - The port GGPO should bind to for UDP traffic. */ start_session :: proc(session: ^^Session, cb: ^SessionCallbacks, game: cstring, num_players: c.int, input_size: c.int, localport: u16) -> ErrorCode --- /* * add_player -- * * Must be called for each player in the session (e.g. in a 3 player session, must * be called 3 times). * * player - A Player struct used to describe the player. * * handle - An out parameter to a handle used to identify this player in the future. * (e.g. in the on_event callbacks). */ add_player :: proc(session: ^Session, player: ^Player, handle: ^PlayerHandle) -> ErrorCode --- /* * start_synctest -- * * Used to being a new GGPO.net sync test session. During a sync test, every * frame of execution is run twice: once in prediction mode and once again to * verify the result of the prediction. If the checksums of your save states * do not match, the test is aborted. * * cb - A SessionCallbacks structure which contains the callbacks you implement * to help GGPO.net synchronize the two games. You must implement all functions in * cb, even if they do nothing but 'return true'; * * game - The name of the game. This is used internally for GGPO for logging purposes only. * * num_players - The number of players which will be in this game. The number of players * per session is fixed. If you need to change the number of players or any player * disconnects, you must start a new session. * * input_size - The size of the game inputs which will be passsed to add_local_input. * * frames - The number of frames to run before verifying the prediction. The * recommended value is 1. * */ start_synctest :: proc(session: ^^Session, cb: ^SessionCallbacks, game: cstring, num_players: c.int, input_size: c.int, frames: c.int) -> ErrorCode --- /* * start_spectating -- * * Start a spectator session. * * cb - A SessionCallbacks structure which contains the callbacks you implement * to help GGPO.net synchronize the two games. You must implement all functions in * cb, even if they do nothing but 'return true'; * * game - The name of the game. This is used internally for GGPO for logging purposes only. * * num_players - The number of players which will be in this game. The number of players * per session is fixed. If you need to change the number of players or any player * disconnects, you must start a new session. * * input_size - The size of the game inputs which will be passsed to add_local_input. * * local_port - The port GGPO should bind to for UDP traffic. * * host_ip - The IP address of the host who will serve you the inputs for the game. Any * player partcipating in the session can serve as a host. * * host_port - The port of the session on the host */ start_spectating :: proc(session: ^^Session, cb: ^SessionCallbacks, game: cstring, num_players: c.int, input_size: c.int, local_port: u16, host_ip: cstring, host_port: u16) -> ErrorCode --- /* * close_session -- * Used to close a session. You must call close_session to * free the resources allocated in start_session. */ close_session :: proc(session: ^Session) -> ErrorCode --- /* * set_frame_delay -- * * Change the amount of frames ggpo will delay local input. Must be called * before the first call to synchronize_input. */ set_frame_delay :: proc(session: ^Session, player: PlayerHandle, frame_delay: c.int) -> ErrorCode --- /* * idle -- * Should be called periodically by your application to give GGPO.net * a chance to do some work. Most packet transmissions and rollbacks occur * in idle. * * timeout - The amount of time GGPO.net is allowed to spend in this function, * in milliseconds. */ idle :: proc(session: ^Session, timeout: c.int) -> ErrorCode --- /* * add_local_input -- * * Used to notify GGPO.net of inputs that should be trasmitted to remote * players. add_local_input must be called once every frame for * all player of type PLAYERTYPE_LOCAL. * * player - The player handle returned for this player when you called * add_local_player. * * values - The controller inputs for this player. * * size - The size of the controller inputs. This must be exactly equal to the * size passed into start_session. */ add_local_input :: proc(session: ^Session, player: PlayerHandle, values: rawptr, size: c.int) -> ErrorCode --- /* * synchronize_input -- * * You should call synchronize_input before every frame of execution, * including those frames which happen during rollback. * * values - When the function returns, the values parameter will contain * inputs for this frame for all players. The values array must be at * least (size * players) large. * * size - The size of the values array. * * disconnect_flags - Indicated whether the input in slot (1 << flag) is * valid. If a player has disconnected, the input in the values array for * that player will be zeroed and the i-th flag will be set. For example, * if only player 3 has disconnected, disconnect flags will be 8 (i.e. 1 << 3). */ synchronize_input :: proc(session: ^Session, values: rawptr, size: c.int, disconnect_flags: ^c.int) -> ErrorCode --- /* * disconnect_player -- * * Disconnects a remote player from a game. Will return ERRORCODE_PLAYER_DISCONNECTED * if you try to disconnect a player who has already been disconnected. */ disconnect_player :: proc(session: ^Session, player: PlayerHandle) -> ErrorCode --- /* * advance_frame -- * * You should call advance_frame to notify GGPO.net that you have * advanced your gamestate by a single frame. You should call this everytime * you advance the gamestate by a frame, even during rollbacks. GGPO.net * may call your save_state callback before this function returns. */ advance_frame :: proc(session: ^Session) -> ErrorCode --- /* * get_network_stats -- * * Used to fetch some statistics about the quality of the network connection. * * player - The player handle returned from the add_player function you used * to add the remote player. * * stats - Out parameter to the network statistics. */ get_network_stats :: proc(session: ^Session, player: PlayerHandle, stats: ^NetworkStats) -> ErrorCode --- /* * set_disconnect_timeout -- * * Sets the disconnect timeout. The session will automatically disconnect * from a remote peer if it has not received a packet in the timeout window. * You will be notified of the disconnect via a EVENTCODE_DISCONNECTED_FROM_PEER * event. * * Setting a timeout value of 0 will disable automatic disconnects. * * timeout - The time in milliseconds to wait before disconnecting a peer. */ set_disconnect_timeout :: proc(session: ^Session, timeout: c.int) -> ErrorCode --- /* * set_disconnect_notify_start -- * * The time to wait before the first EVENTCODE_NETWORK_INTERRUPTED timeout * will be sent. * * timeout - The amount of time which needs to elapse without receiving a packet * before the EVENTCODE_NETWORK_INTERRUPTED event is sent. */ set_disconnect_notify_start :: proc(session: ^Session, timeout: c.int) -> ErrorCode --- /* * log -- * * Used to write to the ggpo.net log. In the current versions of the * SDK, a log file is only generated if the "quark.log" environment * variable is set to 1. This will change in future versions of the * SDK. */ log :: proc(session: ^Session, fmt: cstring, #c_vararg args: ..any) --- /* * logv -- * * A varargs compatible version of log. See log for * more details. */ logv :: proc(session: ^Session, fmt: cstring, args: c.va_list) --- }