def Server_Snapshot_Update(client, networker, game, event):
# Copy the current game state, and replace it with everything the server knows
packet_time = round(struct.unpack_from(">f", event.bytestr)[0], 3)
event.bytestr= event.bytestr[4:]
if len(game.old_states) > 0:
tmp = game.old_states
tmp.sort(key=lambda x: x.time)
#if tmp != game.old_states:
# print([s.time for s in game.old_states])
old_state_times = [old_state.time for old_state in game.old_states]
if max(old_state_times) > packet_time:
if packet_time in old_state_times:
# The packet time miraculously is equal one of the stored states
state = game.old_states[old_state_times.index(packet_time)]
else:
# it isn't, we gotta interpolate between the two nearest
sorted_times = old_state_times
sorted_times.sort(key=lambda state_time: abs(state_time - packet_time))
state_1 = game.old_states[old_state_times.index(sorted_times[0])]
state_2 = game.old_states[old_state_times.index(sorted_times[1])]
state = state_1.copy()
state.interpolate(state_1, state_2, (packet_time - sorted_times[0]) / (sorted_times[1] - sorted_times[0]))
else:
state = game.current_state
# Delete all the old states, they are useless. Remember that list is chronologically ordered
while len(game.old_states) > 0:
if game.old_states[0].time <= packet_time:
game.old_states.pop(0)
else:
break
# Also delete those too far ahead
server_current_time = packet_time + networker.estimated_ping
while len(game.old_states) > 0:
if game.old_states[-1].time >= packet_time + min(networker.estimated_ping, constants.MAX_EXTRAPOLATION):
game.old_states.pop(-1)
else:
break
else:
state = game.current_state
if state.time < packet_time:
state.update_all_objects(game, packet_time-state.time)
#try:
# print("game.old_states: {}\n".format([s.time for s in game.old_states]), "{0} < {1} < {2}\n".format(state_1.time, state.time, state_2.time), "packet time:{}\n".format(packet_time), "server time:{}\n".format(packet_time+networker.estimated_ping))
#except:
# print("game.old_states: {}\n".format([s.time for s in game.old_states]), "state.time:{0}\n".format(state.time),"current_state.time:{}\n".format(game.current_state.time), "state.time-current_state.time:{}\n".format(state.time - game.current_state.time), "packet time:{}\n".format(packet_time), "server time:{}\n".format(packet_time+networker.estimated_ping))
# State should now be exactly what the client thinks should happen at packet_time. Now let the server correct that assumption
for player in state.players.values():
length = player.deserialize_input(event.bytestr)
event.bytestr = event.bytestr[length:]
try:
character = state.entities[player.character_id]
length = character.deserialize(state, event.bytestr)
event.bytestr = event.bytestr[length:]
except KeyError:
# Character is dead; continue
pass
# Now we have exactly what happened on the server at packet_time, update it to packet_time+ping (which also happens to be the length of all old_states)
#state.update_all_objects(game, networker.estimated_ping)
# Update this state with all the input information that appeared in the meantime
for old_state in game.old_states:
state.update_synced_objects(game, min(constants.PHYSICS_TIMESTEP, old_state.time - state.time))
old_player = old_state.players[client.our_player_id]
input = old_player.serialize_input()
player = state.players[client.our_player_id]
player.deserialize_input(input)
game.current_state = state
NAGN, where should I push this? It pretty much works, aka I think the client emulates what's happening on the server pretty well, although I couldn't do a long-range hosting test yet. Also, it's totally not smooth, there's warping (which is supposed to be there), so I'll have to take a look at buffering stuff and using it for the interpolation.