diff options
| author | gingerBill <bill@gingerbill.org> | 2022-05-09 23:32:23 +0100 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2022-05-09 23:32:23 +0100 |
| commit | 0d4e710b965cb0808f99f6d0fa769f554000c20d (patch) | |
| tree | 4615528410e0539e5830aacf9434c153564acbfb | |
| parent | 205aa10b88c7e089dd6ae4bd76a768f4de682fe3 (diff) | |
Add `vendor:ggpo`
| -rw-r--r-- | vendor/README.md | 8 | ||||
| -rw-r--r-- | vendor/ggpo/GGPO.lib | bin | 0 -> 3403590 bytes | |||
| -rw-r--r-- | vendor/ggpo/LICENSE | 21 | ||||
| -rw-r--r-- | vendor/ggpo/ggpo.odin | 526 |
4 files changed, 555 insertions, 0 deletions
diff --git a/vendor/README.md b/vendor/README.md index 14e91ca89..628ea2727 100644 --- a/vendor/README.md +++ b/vendor/README.md @@ -119,6 +119,14 @@ See also LICENSE.txt in the `portmidi` directory itself. See also LICENSE in the `ENet` directory itself.
+## GGPO
+
+[GGPO](https://www.ggpo.net/) GGPO Rollback Networking SDK.
+
+Zero-input latency networking library for peer-to-peer games.
+
+See also LICENSE in the `GGPO` directory itself.
+
## Botan
[Botan](https://botan.randombit.net/) Crypto and TLS library.
diff --git a/vendor/ggpo/GGPO.lib b/vendor/ggpo/GGPO.lib Binary files differnew file mode 100644 index 000000000..70feb57da --- /dev/null +++ b/vendor/ggpo/GGPO.lib diff --git a/vendor/ggpo/LICENSE b/vendor/ggpo/LICENSE new file mode 100644 index 000000000..49e89062c --- /dev/null +++ b/vendor/ggpo/LICENSE @@ -0,0 +1,21 @@ +The MIT License + +Copyright (c) 2009-2019 GroundStorm Studios, LLC. (http://ggpo.net) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.
\ No newline at end of file diff --git a/vendor/ggpo/ggpo.odin b/vendor/ggpo/ggpo.odin new file mode 100644 index 000000000..c727e4a67 --- /dev/null +++ b/vendor/ggpo/ggpo.odin @@ -0,0 +1,526 @@ +package 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 {}, + remove: 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) --- +}
\ No newline at end of file |