Skip to content

Commit

Permalink
aoeuoeu
Browse files Browse the repository at this point in the history
  • Loading branch information
minimapletinytools committed Aug 23, 2024
1 parent f89b071 commit c075727
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 21 deletions.
51 changes: 39 additions & 12 deletions TODO.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,37 +5,61 @@ things it needs to do
-manage initial game sync


startup process
:: 7/2024 startup process
-all players join, expect them to have GGPO initialized (to set up event listeners)
SKIP-send synchronization event, wait to receive synchronization event response for all players
-send start event, include server_synch_start_time https://create.roblox.com/docs/reference/engine/globals/RobloxGlobals
-upon receiving start event, start GGPO at time server_synch_start_time + 3 sec - ping https://create.roblox.com/docs/reference/engine/classes/Player#GetNetworkPing


:: 7/2/2024 disconnect notes
-need download game state (at ggporoblox level) that initialize ggpo with correct information at given frame
-and adds appropriate frame data info to CARS
-is there a P2P version of mid game join? NO
-no disconnect handling, since one player DC means desync
-so you just have that players input in prediction mode indefinitely, NBD, may result in big rollback
-but in that case either
-CARS can either disconnect that player (not allow old inputs when that player joins)
-pause the game and wait for player
-stop the game due to player drop
-you want to make sure all players have the same prediction for that player though, should befine.
-in the future you might have a disconnect consensus algorithm or osmething to handle such cases
-cars tracks DC state of players, specifically if no input has bene received, the player is "DC'd" and not allowed to send old inputs until they reconnect
-you need a way to force that player to drop its own inputs (perhaps using CARS authoritative input or just reinitializing that peers GGPO)
-you could also just restart that client
-same algo can be used when player actually quits and rejoins



## NEW WIP
-cars disconnect handling (see notes above)
-explicit init
-just need to update UDPProto_LazyInitPlayer everything else is OK to lazy init I think
-are you sure though?

## WIP TODO IGNORE
DONE-consider getting rid of the J parameter for gamestate stuff?

-pull out utility methods into its own file
-maybe pull out types into its own file
-fix udpproto owner data lastFrame issue
-causing harmless asserts to hit due to udproto tryig to pass on nil inputs from the owner
-fix lazy init tracking problems

-fix lazy init tracking problems (probably by adding explicit init routine)
-- TODO this won't always work due to lazy init. If we have a lazy init player, we won't have a lastFrame for them in the map, and we will confirm past their frames which is bad :(
-should you just have an explicit setup routine? and save lazy init for players being added mid game
-this will still have the problem where you don't know about a lazy init player and discard confirmed frames after their inputs you don't know about
-you can solve this wil explicit player add packets though that force the lazy init of those players

-cleanup logging
-maybe replace frameNull with nil...
-MockGame Functionality
-out of order packets
DONE/SORTOF-repeat test with UDPPROTO_NO_QUEUE_NIL_INPUT
-also move UDPPROTO_NO_QUEUE_NIL_INPUT into config
-more tests
DONE-CARS test
DONE-force longer desync
-component tests for
-inputqueue
-sync
-out of order packets in MockGame
-cleanup routine for savedstate in synced
-add override and consistency assert in InputQueue_AddInput
DONE-need to dinstguish between local input and remote input and local player remote input
Expand All @@ -44,13 +68,12 @@ DONE/SORTOF-repeat test with UDPPROTO_NO_QUEUE_NIL_INPUT
-ideally the same mechanism can be used to assert/override inputs that arrive out of order or from non auth peers
-Pretty sure you need to let sync know somehow that inputs were overridden

-udpproto to support spectator mode
V2-udpproto to support spectator mode
-reject/assert/log on input
-player number is spectator
-add disconnect tracking
-figure out what to do when player is disconnect
-refer to orig ggpo implementation
-allow dynamic player entry/exit

V2-allow dynamic player entry/exit
-need methods to initialize at given frame/state
-probbaly have a server input for such events
-startgame + player data (frame 0 input)
-maybe have an all players synced msg (when all players have reasonable rift) (probbaly not needed)
Expand All @@ -69,7 +92,11 @@ V2-figure out how to handle initial player data
-prob best just to recommend X frames for syncing initial state and rift
-send player data as server input on frame 0


IGNORE/DONE-add disconnect tracking
IGNORE/DONE-figure out what to do when player is disconnect
-refer to orig ggpo implementation
DONE/SORTOF-repeat test with UDPPROTO_NO_QUEUE_NIL_INPUT
-also move UDPPROTO_NO_QUEUE_NIL_INPUT into config
DONE-make all functions local
DONE-inputqueue needs explicit las frame tracking because sometimes we clear out all the cnofirmed frames
DONE-isprodxy is udpproto is wrong, you need to have ggpo peer take the input and share with other udpportos
Expand Down
Binary file modified ggpo-roblox.rbxl
Binary file not shown.
15 changes: 9 additions & 6 deletions src/shared/ggpo.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1188,11 +1188,6 @@ local function UDPProto_new<I>(owner : PlayerHandle, player : PlayerHandle, endp
local playerData = {}
playerData[owner] = UDPProto_Player_new()

-- DELETE
--for _, proxy in pairs(player.proxy) do
-- playerData[proxy] = UDPProto_Player_new()
--end

local r = {
owner = owner,
player = player,
Expand Down Expand Up @@ -1252,6 +1247,8 @@ local function UDPProto_new<I>(owner : PlayerHandle, player : PlayerHandle, endp
return r
end

-- TODO don't allow lazy player init
-- replace these calls with an assert and do pre init when calling GGPO_Peer_AddPlayer
local function UDPProto_LazyInitPlayer<I>(udpproto : UDPProto<I>, player : PlayerHandle) : UDPProto_Player<I>
local r = udpproto.playerData[player]
if r == nil then
Expand Down Expand Up @@ -1652,6 +1649,8 @@ local function GGPO_Peer_AddPeer<T,I>(peer : GGPO_Peer<T,I>, player : PlayerHand
assert(peer.udps[player] == nil, "expected peer to not already exist")
peer.udps[player] = UDPProto_new(peer.player, player, endpoint)

-- TODO init peer in Sync

if peer.isProxy then
Tomato(ctx(peer), peer.sync.framecount == frameInit, "adding peers after frameInit not supported")
-- TODO send most recently synced state to newly added peer
Expand Down Expand Up @@ -1763,9 +1762,11 @@ local function GGPO_Peer_DoPoll<T,I>(peer : GGPO_Peer<T,I>)
-- do rollback if needed
local rollback_frame = Sync_CheckSimulation(peer.sync)

-- TODO should be ok to uncomment?
--if peer.udps[carsHandle] then
-- we should never rollback past the last received frame from cars (which is authoritative)
-- TODO note that subscribe calls are asynchronous so the below may fail if the script has yielded since the last time we polled for events and updated Sync
-- TODO note that subscribe calls are asynchronous so the below may fail if the script has yielded since the last time we polled for events and updated Sync
-- WAIT no, I think this is ok, because we polled just earlier in this function so it should not have yielded between then and now.
--assert(rollback_frame >= peer.udps[carsHandle].lastReceivedFrame )
--end

Expand All @@ -1778,8 +1779,10 @@ local function GGPO_Peer_DoPoll<T,I>(peer : GGPO_Peer<T,I>)
local total_min_confirmed = current_frame - 1

for player, udp in pairs(peer.udps) do

-- TODO this won't always work due to lazy init. If we have a lazy init player, we won't have a lastFrame for them in the map, and we will confirm past their frames which is bad :(
local lastSyncFrame = UDPProto_lastSynchronizedFrame(udp)

-- TODO NOTE this is different than original GGPO in P2P case, in original GGPO, the peer has the last received frame and connected status for all peers connected to player (N^2 pieces of data)
-- and takes the min of all those. I don't quite know why it does this at all, doing just one hop here seems sufficient/better. I guess because we might be disconnected to the peer so we rely on relayed information to get the last frame?
total_min_confirmed = math.min(lastSyncFrame, total_min_confirmed)
Expand Down
1 change: 1 addition & 0 deletions src/shared/util/bimap.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
--!strict
-- bimap implementation in Lua
-- this version allocates functions for each instance :(

type Bimap_<K,V> = {

Expand Down
2 changes: 1 addition & 1 deletion src/shared/util/bimap_prototype.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
--!strict
-- bimap implementation in Lua
-- same as the other bimap, except with the prototype pattern
-- same as the other bimap, except with the prototype pattern (so functions only need to be allocated once)
-- doesn't work due to typeof(setmetatable({} :: BimapData<K,V>, {} :: BimapImpl<K,V> & BimapMT<K,V>)) not propogating the types down

type BimapData<K,V> = {
Expand Down
4 changes: 2 additions & 2 deletions src/shared/util/queue.lua
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
--!strict
-- Queue implementation in Lua
-- more efficient than table.insert/remove which reindexes the table
-- this version allocates functions for each instance :(

type QueueImpl<T> = {
--__index: QueueImpl<T>,
equeue: (self: Queue<T>, x: T) -> (),
enqueue: (self: Queue<T>, x: T) -> (),
dequeue: (self: Queue<T>) -> T?,

queue : {[number] : T},
Expand Down

0 comments on commit c075727

Please sign in to comment.