Skip to content

Commit

Permalink
Implement #163
Browse files Browse the repository at this point in the history
  • Loading branch information
AmonGruenwald committed Dec 16, 2021
1 parent 1ebbd61 commit ab2bf1e
Show file tree
Hide file tree
Showing 6 changed files with 324 additions and 139 deletions.
127 changes: 127 additions & 0 deletions Shared/GhostManagerBase.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
extends Node
class_name GhostManager

signal ghost_hit(victim_player_id, victim_timeline_index, perpetrator_player_id, perpetrator_timeline_index)
signal quiet_ghost_hit(victim_player_id, victim_timeline_index, perpetrator_player_id, perpetrator_timeline_index)
signal new_record_data_applied(player)

onready var _server = get_node("/root/Server")
onready var _max_ghosts = Constants.get_value("ghosts", "max_amount")


var _game_manager
var _round_manager
var _action_manager
var _character_manager

# Timeline index <-> ghost
# holds every ghost
var _ghosts: Array = []

var _game_phase_start_time = -1


func _ready():
set_physics_process(false)


func _physics_process(delta):
_update_ghosts(delta)



func init(game_manager,round_manager,action_manager, character_manager):
_game_manager = game_manager
_round_manager = round_manager
_action_manager = action_manager
_character_manager = character_manager
set_physics_process(true)
_spawn_all_ghosts()
_disable_all_ghosts()
_move_ghosts_to_spawn()


func on_preparation_phase_started() -> void:
_stop_ghosts()
_move_ghosts_to_spawn()


func on_countdown_phase_started() -> void:
pass


func on_game_phase_started() -> void:
_game_phase_start_time = _server.get_server_time()
_start_ghosts(_game_phase_start_time)


func on_game_phase_stopped() -> void:
_use_new_record_data()


# ABSTRACT #
func _spawn_all_ghosts():
assert(false) #this must be overwritten in child class


# ABSTRACT #
func _enable_active_ghosts() -> void:
assert(false) #this must be overwritten in child class


# ABSTRACT #
func _use_new_record_data():
assert(false) #this must be overwritten in child class


# ABSTRACT #
func _on_ghost_hit(perpetrator, victim):
assert(false) #this must be overwritten in child class


# gets called every physics frame
func _update_ghosts(delta):
for ghost in _ghosts:
ghost.update(delta)


func _create_ghost(player_id, team_id, timeline_index, spawn_point, ghost_scene):
var ghost = ghost_scene.instance()
add_child(ghost)
ghost.init(_action_manager, player_id, team_id, timeline_index, spawn_point)
return ghost


func _update_ghost_record(ghost_array, timeline_index, record_data, round_index):
ghost_array[timeline_index].set_record_data(record_data)
ghost_array[timeline_index].round_index = round_index


func _move_ghosts_to_spawn() -> void:
for ghost in _ghosts:
ghost.move_to_spawn_point()


func refresh_active_ghosts():
_disable_all_ghosts()
_enable_active_ghosts()


func _disable_all_ghosts() -> void:
for ghost in _ghosts:
ghost.disable_body()


func _start_ghosts(start_time) -> void:
for ghost in _ghosts:
ghost.start_playing(start_time)


func _stop_ghosts() -> void:
for ghost in _ghosts:
ghost.stop_playing()





148 changes: 148 additions & 0 deletions Shared/ServerGhostManager.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
extends GhostManager
class_name ServerGhostManager

var _ghost_scene = preload("res://Shared/Characters/GhostBase.tscn")


# holds ghosts split by team_id
var _seperated_ghosts: Array = [[],[]]


# previous deaths that could be relevant for current round
var _previous_ghost_deaths: Array = []
# deaths we recorded during the current round (will get added to above array after the round)
var _new_previous_ghost_death: Array = []
# previous deaths are ordered by time so we only ever have to check one index
# and only after it's time has been reached, the following ones could be relevant
var _current_ghost_death_index = 0


# OVERRIDE #
func on_game_phase_started() -> void:
_refresh_previous_ghost_deaths()
.on_game_phase_started()


# OVERRIDE #
func _update_ghosts(delta):
_look_for_previous_death()
._update_ghosts(delta)


# OVERRIDE ABSTRACT #
func _spawn_all_ghosts():
for timeline_index in range(_max_ghosts+1):
for team_id in [0,1]:
var spawn_point = _game_manager.get_spawn_point(team_id, timeline_index)
var player_id = _character_manager.team_id_to_player_id(team_id)
var ghost = _create_ghost(player_id, team_id, timeline_index, spawn_point, _ghost_scene)
ghost.connect("hit", self, "_on_ghost_hit", [ghost])
_seperated_ghosts[team_id].append(ghost)
_ghosts.append(ghost)


# OVERRIDE ABSTRACT #
func _enable_active_ghosts() -> void:
for team_id in [0,1]:
for timeline_index in range(0, _max_ghosts+1):
var player_id = _character_manager.team_id_to_player_id(team_id)
if timeline_index != _character_manager.player_dic[player_id].timeline_index:
if _seperated_ghosts[team_id][timeline_index].is_record_data_set():
_seperated_ghosts[team_id][timeline_index].enable_body()


# OVERRIDE ABSTRACT #
func _use_new_record_data():
var current_round_index = _round_manager.round_index-1
for player in _character_manager.player_dic.values():
var record_data = player.get_record_data()
_update_ghost_record(_seperated_ghosts[player.team_id], record_data.timeline_index, record_data, current_round_index)
_seperated_ghosts[player.team_id][record_data.timeline_index].player_id = player.player_id
emit_signal("new_record_data_applied", player)


# OVERRIDE ABSTRACT #
func _on_ghost_hit(perpetrator, victim):
_new_previous_ghost_death.append(_create_new_ghost_death_data(victim, perpetrator))
emit_signal("ghost_hit",victim.player_id, victim.timeline_index, perpetrator.player_id, perpetrator.timeline_index)


func _on_player_killed(victim, perpetrator):
#when an active player is killed we also have to create a ghost death so the death is fixed for the following rounds
_new_previous_ghost_death.append(_create_new_ghost_death_data(victim, perpetrator))


func _is_ghost_active(team_id, round_index, timeline_index):
var ghost = _seperated_ghosts[team_id][timeline_index]
# check if ghost stored at timeline index was recorded for the passed round
if ghost.round_index == round_index:
return ghost.is_active() and ghost.is_playing()
else:
return false


func _refresh_previous_ghost_deaths():
var current_round_index = _round_manager.round_index
_add_new_previous_ghost_deaths_data()
for player in _character_manager.player_dic.values():
_clear_old_ghost_death_data(player.team_id, player.timeline_index, current_round_index)
_current_ghost_death_index = 0


func _look_for_previous_death():
if _round_manager.get_current_phase() != RoundManager.Phases.GAME:
return
if _current_ghost_death_index >= _previous_ghost_deaths.size():
return
var current_time = _server.get_server_time()-_game_phase_start_time
while _previous_ghost_deaths[_current_ghost_death_index].time < current_time:
_apply_previous_death(_previous_ghost_deaths[_current_ghost_death_index])
_current_ghost_death_index+=1
if _current_ghost_death_index >= _previous_ghost_deaths.size():
break


func _apply_previous_death(ghost_death_data):
var victim_active = _is_ghost_active(ghost_death_data.victim_team_id,ghost_death_data.victim_round_index,ghost_death_data.victim_timeline_index)
var perpetrator_active = _is_ghost_active(ghost_death_data.perpetrator_team_id,ghost_death_data.perpetrator_round_index,ghost_death_data.perpetrator_timeline_index)
if victim_active and perpetrator_active:
var victim = _seperated_ghosts[ghost_death_data.victim_team_id][ghost_death_data.victim_timeline_index]
var perpetrator = _seperated_ghosts[ghost_death_data.perpetrator_team_id][ghost_death_data.perpetrator_timeline_index]
emit_signal("quiet_ghost_hit", victim.player_id, victim.timeline_index, perpetrator.player_id, perpetrator.timeline_index)
victim.quiet_hit(perpetrator)


func _clear_old_ghost_death_data(perpetrator_team_id, perpetrator_timeline_index, perpetrator_round_index):
var to_remove = []
for data in _previous_ghost_deaths:
if data.perpetrator_team_id == perpetrator_team_id and data.perpetrator_timeline_index == perpetrator_timeline_index:
if data.perpetrator_round_index < perpetrator_round_index:
to_remove.append(data)
for data in to_remove:
_previous_ghost_deaths.erase(data)


func _create_new_ghost_death_data(victim, perpetrator):
var ghost_data = GhostDeathData.new()

ghost_data.time = _server.get_server_time()-_game_phase_start_time

ghost_data.victim_team_id = victim.team_id
ghost_data.victim_round_index = victim.round_index
ghost_data.victim_timeline_index = victim.timeline_index

ghost_data.perpetrator_team_id = perpetrator.team_id
ghost_data.perpetrator_round_index = perpetrator.round_index
ghost_data.perpetrator_timeline_index = perpetrator.timeline_index

return ghost_data


func _add_new_previous_ghost_deaths_data():
_previous_ghost_deaths += _new_previous_ghost_death
_new_previous_ghost_death.clear()
_previous_ghost_deaths.sort_custom(self, "_costum_compare_ghost_death")


func _costum_compare_ghost_death(a, b):
return a.time < b.time
29 changes: 4 additions & 25 deletions recursio-client/Managers/ClientGhostManager.gd
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,7 @@ func on_game_phase_started() -> void:
_toggle_ghost_animation(true)


# OVERRIDE #
func on_game_phase_stopped() -> void:
.on_game_phase_stopped()


# OVERRIDE #
# OVERRIDE ABSTRACT #
func _spawn_all_ghosts():
for timeline_index in range(_max_ghosts+1):
var player_id = _character_manager._player.player_id
Expand All @@ -68,9 +63,8 @@ func _spawn_all_ghosts():
_ghosts.append(enemy_ghost)


# OVERRIDE #
# OVERRIDE ABSTRACT #
func _enable_active_ghosts() -> void:
# Not calling super here because client and server have completely different concepts of ghost seperation - player/enemy and player[0]/player[1]
for timeline_index in range(_max_ghosts+1):
if timeline_index != _character_manager._player.timeline_index:
if _player_ghosts[timeline_index].is_record_data_set():
Expand All @@ -81,10 +75,8 @@ func _enable_active_ghosts() -> void:
_enemy_ghosts[timeline_index].enable_body()


# OVERRIDE #
# OVERRIDE ABSTRACT #
func _use_new_record_data():
# Not calling super because we dont want local values to overwrite remote ones
# But we will use them until we get better ones
var current_round_index = _round_manager.round_index-1
var record_data = _character_manager._player.get_record_data()
if current_round_index > _player_ghosts[record_data.timeline_index].round_index:
Expand All @@ -97,25 +89,12 @@ func _use_new_record_data():
_enemy_ghosts[record_data.timeline_index].player_id = _character_manager._enemy.player_id


# OVERRIDE #
# OVERRIDE ABSTRACT #
func _on_ghost_hit(_perpetrator, _victim):
# local ghost hits should not trigger anything on the client
pass


# OVERRIDE #
func _refresh_previous_ghost_deaths():
#again having to override this because of different concepts in charactermanager
var current_round_index = _round_manager.round_index
_add_new_previous_ghost_deaths_data()
var player = _character_manager._player
var enemy = _character_manager._enemy
_clear_old_ghost_death_data(player.team_id, player.timeline_index, current_round_index)
_clear_old_ghost_death_data(enemy.team_id, enemy.timeline_index, current_round_index)
_current_ghost_death_index = 0
_game_phase_start_time = _server.get_server_time()


func on_player_ghost_record_received(timeline_index, round_index, record_data):
_update_ghost_record(_player_ghosts, timeline_index, record_data , round_index)
_update_ghost_paths()
Expand Down
2 changes: 1 addition & 1 deletion recursio-server/GameRoom/GameRoomWorld.tscn
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
[ext_resource path="res://Shared/Actions/ActionManager.gd" type="Script" id=4]
[ext_resource path="res://GameRoom/GameManager.gd" type="Script" id=5]
[ext_resource path="res://GameRoom/GameRoomWorld.gd" type="Script" id=6]
[ext_resource path="res://Shared/GhostManager.gd" type="Script" id=7]
[ext_resource path="res://GameRoom/ServerGhostManager.gd" type="Script" id=7]

[node name="GameRoomWorld" type="Node"]
script = ExtResource( 6 )
Expand Down
Loading

0 comments on commit ab2bf1e

Please sign in to comment.