Phame utilizes an interaction-based networking system which performs all actions client-side.
Clients request identified interactions to the server, which simply reflects the request out to all clients to perform the interaction.
The advantage to this is the game operates basically the same wether doing local multiplayer with everyone on one machine, or network player.
The disadvantage is the potential for race conditions and cheating since each individual client is responsible for veryifing an interaction is possible.
Interaction-based netwokring modifies the Action System to allow clients over a network to interact.

obj_server receives a reliable CLIENT_CONNET message and calls server_connect_client which creates Connected_client
Interactions to perform must have all details specified and not up to interpretation by the client. This prevents desync scenarios. Details can be specified by the requesting client or authoritatively by the server before reflecting out. The choice of when depends on whether the client has the authority to specify the detials.
For example, when a player's block freezes in the air for DFnI, is determined by that player's client since it needs to be predictable by the player.
Iteractions occur the same way for every client, but sometimes special feedback is required to the requesting client. For example, when asking to join the game, the resulting game_player_id is determined by the server.
Clients can request authoritatve information using an INFORMATION_CMD for things like what player_id to use for a new joining player.
With Phame Networking v1.3.4, interaction sturctures, debug, and a standardized method to reduce requests was implemented.
Instead of specialized client request functions for each possible parameter combination, a consistent interaction structure will now be used across client request, server approvals, client receiving, and client performance of interactions.
In an interactable's request_action, the specific request_interaction_x() is now replaced with the creation of a stc_interaction.
For example,
request_interaction_u8_string(interactable_id, interaction, ready_to_start, game_player_name)
Would be changed to:
// Customize interaction parameters, buffer is deleted after request is sent
var interaction_body = buffer_create(2, buffer_grow, BUFFER_ALIGNMENT)
buffer_write(interaction_body, buffer_u8, ready_to_start)
buffer_write(interaction_body, buffer_string, game_player_name)
// Create and request interaction
var interaction = new stc_interaction(-1, action, interactable_id, interaction_body)
client_request_interaction(interaction)
This system allows infinite interaction parameter customization without requiring changes on the Phame Networking module to provide specific client request functions moving forward. Note the size and type of buffer created, 2, buffer_grow. For many cases where the input is known, the specific amount of bytes can be specified with a buffer_fixed.
For read_interaction, add buffer_seek(buff, buffer_seek_start, 0) as the first line and outside of the switch statement to address the new interaction_body buffer.
Interaction logging is built into interaction performance, with implentation determined by scr_networking_client_interface.
Add a debug_interaction function to each interactable by copying the read_interaction function, but return a string describing the optional parameters instead of performing the action with them.
To standardize the method to ensure only one request is sent at a time, the interaction available system was developed.
The system works by utilizing a ds_map, (which allows the action constants to be the keys to values) and stores a flag for each action on whether it can be requested. Depending on the implementation, the system can make an action a one-time request, or reset the flag upon performance of the action.
To add the system to an interactable, initialize the ds_map for the actions in the interactable Create Event:
interaction_available = ds_map_create()
ds_map_add(interaction_available, ACT_RESPAWN, true)
ds_map_add(interaction_available, ACT_ESCAPE, true)
Under request_action add a conditional prior to the actual request:
if interaction_available[? action] {
// Request interaction
interaction_available[? action] = false
}
The availability flag can be reset upon performance by modifiying perform_action with:
interaction_available[? action] = true
Any interactable using the interaction available system require the ds_map to be cleaned up with a Clean Up Event:
/// @description Clean up
ds_map_destroy(interaction_available)
The Interaction Available System can be utilized to replace the tracking of separate states. For example, tracking whether a lever is on or off:
Create Event
lever_on = false
previous_lever_on = lever_on
Step Event
if place_meeting(x, y, obj_character) {
lever_on = true
}
else {
lever_on = false
}
if lever_on != previous_lever_on {
previous_lever_on = lever_on
request_action(ACT_ACTIVATE, lever_on)
}