Browse Source

Add `vendor:ggpo`

gingerBill 3 years ago
parent
commit
0d4e710b96
4 changed files with 555 additions and 0 deletions
  1. 8 0
      vendor/README.md
  2. BIN
      vendor/ggpo/GGPO.lib
  3. 21 0
      vendor/ggpo/LICENSE
  4. 526 0
      vendor/ggpo/ggpo.odin

+ 8 - 0
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.

BIN
vendor/ggpo/GGPO.lib


+ 21 - 0
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.

+ 526 - 0
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) ---
+}