Ok, there was LOT of nuance when I was testing this, but by-and-large, this method works.
Firstly, the PEER_LAST_ROUND_TRIP_TIME is very accurate, but slow to update. I figured out the slowness is actually an intended feature from my research on Enet. So that’s good.
Secondly, the PEER_PACKET_LOSS is a bit strange. It’s accurate, but it’s SUPER slow to update (10~ second interval) and it takes a long time to reduce packet loss percentage when it does go up.
Also, when I test artificial packet loss with Clumsy, the percentage shoots up (2.0 packet loss on Clumsy = 20% Enet Packet Loss). That last one could be a misunderstanding with Clumsy though.
Here’s the functions I made for the server to track ping and packet loss:
(They had to be separate in order for me to return their values)
(And if anything but the server calls these, it returns a default value of -1)
func get_client_ping(Client_ID:int) -> float:
if not multiplayer.is_server(): return -1
var Enet_Multiplayer : ENetMultiplayerPeer = multiplayer.multiplayer_peer
var Enet_Peer : ENetPacketPeer = Enet_Multiplayer.get_peer(Client_ID)
var Client_Ping : float = Enet_Peer.get_statistic(ENetPacketPeer.PEER_LAST_ROUND_TRIP_TIME)
return Client_Ping
func get_client_packet_loss(Client_ID:int) -> float:
if not multiplayer.is_server(): return -1
var Enet_Multiplayer : ENetMultiplayerPeer = multiplayer.multiplayer_peer
var Enet_Peer : ENetPacketPeer = Enet_Multiplayer.get_peer(Client_ID)
var Client_Packet_Loss_Percentage : float = Enet_Peer.get_statistic(ENetPacketPeer.PEER_PACKET_LOSS)
return Client_Packet_Loss_Percentage
Thanks, @gertkeno for helping me figure this out. 
Last thing, having to set a variable to set another variable is such a bad design. No wonder I couldn’t figure it out before, it was extremely unintuitive.