first
This commit is contained in:
14
script/ButtonLogicImpulse.gd
Normal file
14
script/ButtonLogicImpulse.gd
Normal file
@@ -0,0 +1,14 @@
|
||||
extends Timer
|
||||
class_name ButtonLogicImpulse
|
||||
|
||||
@export var interactBox: InteractBox
|
||||
signal onPressed
|
||||
|
||||
func _ready() -> void:
|
||||
interactBox.interactedWith.connect(onInteraction)
|
||||
one_shot = true
|
||||
|
||||
func onInteraction(_playerReference: PlayerCharacter) -> void:
|
||||
if is_stopped():
|
||||
onPressed.emit()
|
||||
start()
|
||||
1
script/ButtonLogicImpulse.gd.uid
Normal file
1
script/ButtonLogicImpulse.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cjiiw7cybj24b
|
||||
12
script/ButtonLogicToggle.gd
Normal file
12
script/ButtonLogicToggle.gd
Normal file
@@ -0,0 +1,12 @@
|
||||
extends Node
|
||||
class_name ButtonLogicToggle
|
||||
|
||||
@export var interactBox: InteractBox
|
||||
@export var state: bool = false #Is it on or off? :) hope this helps it is currently 1:42 am
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
interactBox.interactedWith.connect(onInteraction)
|
||||
|
||||
func onInteraction(_playerReference: PlayerCharacter) -> void:
|
||||
state = !state
|
||||
1
script/ButtonLogicToggle.gd.uid
Normal file
1
script/ButtonLogicToggle.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://b0k1i0242ren6
|
||||
42
script/MapLogic.gd
Normal file
42
script/MapLogic.gd
Normal file
@@ -0,0 +1,42 @@
|
||||
extends Node3D
|
||||
class_name MapLogic
|
||||
|
||||
signal onCollision
|
||||
|
||||
signal missionLost
|
||||
|
||||
@export var debugObj: PackedScene
|
||||
@export var pathPivot: Node3D
|
||||
@export var drawDebugCubesPathfinding:= false
|
||||
|
||||
@export var pathfindingGridLoader: PathfindingGridLoader
|
||||
var astar : AStar2D
|
||||
|
||||
@export var playerStartPos: Vector3 = Vector3(0,0,0)
|
||||
|
||||
func _ready() -> void:
|
||||
if pathfindingGridLoader: pathfindingGridLoader.loadGrid()
|
||||
onCollision.emit() #TODO: REMOVE THIS LATER ITS ONLY HERE TO STOP A WARNING
|
||||
|
||||
func looseMission() -> void:
|
||||
missionLost.emit()
|
||||
|
||||
|
||||
func finishAstarSetup() -> void: ##Run this in process or physics process of the child map class
|
||||
if pathfindingGridLoader:
|
||||
if pathfindingGridLoader.loading_done:
|
||||
astar = pathfindingGridLoader.astar
|
||||
print(astar.get_point_count())
|
||||
pathfindingGridLoader.queue_free()
|
||||
|
||||
if drawDebugCubesPathfinding: #Only for debugging
|
||||
for point in astar.get_point_ids():
|
||||
var point_position: Vector2 = astar.get_point_position(point)
|
||||
addObject(debugObj,pathPivot,Vector3(point_position.x,0.2,point_position.y))
|
||||
|
||||
func addObject(AddedObject:PackedScene, Parent: Node, Position: Vector3, Rotation: Vector3= Vector3(0,0,0)):
|
||||
var obj = AddedObject.instantiate()
|
||||
Parent.add_child(obj)
|
||||
obj.position = Position
|
||||
obj.rotation = Rotation
|
||||
return obj
|
||||
1
script/MapLogic.gd.uid
Normal file
1
script/MapLogic.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cbjn7f7r081q8
|
||||
12
script/MissionTask.gd
Normal file
12
script/MissionTask.gd
Normal file
@@ -0,0 +1,12 @@
|
||||
extends Object
|
||||
class_name MissionTask
|
||||
|
||||
var taskName: String = ""
|
||||
var description: String = "?"
|
||||
var completed: bool = false
|
||||
|
||||
var taskLabel: Label
|
||||
|
||||
func _init(nameOfTask: String, descriptionOfTask: String = "?") -> void:
|
||||
taskName = nameOfTask
|
||||
description = descriptionOfTask
|
||||
1
script/MissionTask.gd.uid
Normal file
1
script/MissionTask.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://t10gemetusb
|
||||
116
script/ShipLogic.gd
Normal file
116
script/ShipLogic.gd
Normal file
@@ -0,0 +1,116 @@
|
||||
extends MapLogic
|
||||
class_name ShipLogic
|
||||
|
||||
var main: Main
|
||||
|
||||
var generatorBiomeExists: bool = true
|
||||
|
||||
var levelGenSeed: int = 0
|
||||
|
||||
var lobbyScene: String = "res://Maps/Lobby/Lobby.tscn"
|
||||
|
||||
var roomList: Array[BasicRoom]
|
||||
var generatorRoomList: Array[BasicRoom]
|
||||
var hallwayLights: Array[OmniLight3D]
|
||||
|
||||
var power: bool = false
|
||||
var hullBreached: bool = false
|
||||
var finishingMission: bool = false
|
||||
|
||||
const HULL_BREACHED_CONDITION_DROP_SPEED: float = 0.8
|
||||
var shipCondition: float = 100.0
|
||||
var shipFuel: float = 100.0
|
||||
|
||||
var taskDict: Dictionary = {0: MissionTask.new("FixGenerator","Get the Generator back running.")}
|
||||
|
||||
@export var levelGenerator: LevelGenerator
|
||||
|
||||
#@export var controllRoom: ControlRoom
|
||||
#@export var breakableRoom: CorridorDeadEndBreakable
|
||||
|
||||
func _ready() -> void:
|
||||
main = get_node("/root/Main")
|
||||
levelGenerator.generate(levelGenSeed)
|
||||
|
||||
main.mapScreen.addTask(taskDict[0])
|
||||
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
finishAstarSetup()
|
||||
|
||||
if Multiplayer.alivePlayerDict.size() == 0:
|
||||
looseMission()
|
||||
|
||||
if taskDict[0].completed:
|
||||
power = true
|
||||
updateLights()
|
||||
|
||||
#if hullBreached:
|
||||
#shipCondition -= HULL_BREACHED_CONDITION_DROP_SPEED * delta
|
||||
#updateShipConditionScreen()
|
||||
|
||||
func finishMission() -> void:
|
||||
if finishingMission: return
|
||||
finishingMission = true
|
||||
|
||||
#Might be temp solution
|
||||
var missionSucces: bool = true
|
||||
for key in taskDict:
|
||||
if !taskDict[key].completed:
|
||||
missionSucces = false
|
||||
break
|
||||
|
||||
if missionSucces:
|
||||
main.missionEndScreen.label.text = "Success!"
|
||||
else:
|
||||
main.missionEndScreen.label.text = "Failure!"
|
||||
|
||||
main.displayMissionEndScreen = true
|
||||
await get_tree().create_timer(8).timeout
|
||||
|
||||
main.displayMissionEndScreen = false
|
||||
main.changeMenu(main.hud)
|
||||
|
||||
main.changeMap.rpc(lobbyScene)
|
||||
|
||||
func setSeed(mapSeed: int) -> void:
|
||||
levelGenSeed = mapSeed
|
||||
|
||||
func addRoomToRoomList(room: BasicRoom) -> void:
|
||||
roomList.push_back(room)
|
||||
if room.biomeName == "generator":
|
||||
generatorRoomList.push_back(room)
|
||||
|
||||
func updateLights() -> void:
|
||||
for room in roomList:
|
||||
room.showLights(power)
|
||||
for light in hallwayLights:
|
||||
light.visible = power
|
||||
#Julian was here
|
||||
func solveTask(id: int) -> void:
|
||||
taskDict[id].completed = true
|
||||
main.mapScreen.completeTask(taskDict[id])
|
||||
|
||||
##TODO
|
||||
#func unSolveTask(id: int) -> void:
|
||||
#taskDict[id].completed = false
|
||||
#main.mapScreen.completeTask(taskDict[id])
|
||||
|
||||
func onLevelGenFinished() -> void:
|
||||
if generatorBiomeExists:
|
||||
var mainRoom: Generator = generatorRoomList[0]
|
||||
for n in generatorRoomList.size()-1:
|
||||
mainRoom.cellSpawners.append_array(generatorRoomList[n+1].powerCellSpawners)
|
||||
mainRoom.wireSpawners.append_array(generatorRoomList[n+1].wireSpawners)
|
||||
mainRoom.Ready()
|
||||
|
||||
#func collisionWithAstroid():
|
||||
#onCollision.emit()
|
||||
#hullBreached = true
|
||||
#shipCondition -= 10
|
||||
#if breakableRoom:
|
||||
#breakableRoom.updateWallVisibility(false)
|
||||
#
|
||||
#func updateShipConditionScreen():
|
||||
#if controllRoom:
|
||||
#controllRoom.shipConditionDisplayNumber = clamp(shipCondition + 1,0,100)
|
||||
1
script/ShipLogic.gd.uid
Normal file
1
script/ShipLogic.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://c7ea7hd1t6ucj
|
||||
180
script/audioManager.gd
Normal file
180
script/audioManager.gd
Normal file
@@ -0,0 +1,180 @@
|
||||
extends Node
|
||||
|
||||
var current_sample_rate: int = 48000
|
||||
var has_loopback: bool = false
|
||||
var max_buffer_size: int = 1000
|
||||
var voicechat_player_path : NodePath = ^"VoiceChat"
|
||||
var sample_rate_min : int = 11025
|
||||
var sample_rate_max : int = 48000
|
||||
|
||||
var local_playback: AudioStreamGeneratorPlayback = null
|
||||
var local_voice_buffer: PackedByteArray = PackedByteArray()
|
||||
|
||||
var network_playback: Dictionary[int, AudioStreamGeneratorPlayback] = {}
|
||||
var network_voice_buffer: Dictionary[int, PackedByteArray] = {}
|
||||
|
||||
@onready var loopback_player : AudioStreamPlayer= $/root/Main/VoiceLoopback
|
||||
|
||||
func _ready() -> void:
|
||||
if not Steamworks.is_initiallized:
|
||||
push_warning("[VoiceChat] VoiceChat disabled due to SteamAPI.")
|
||||
return
|
||||
if has_loopback:
|
||||
print("[VoiceChat] Loopback on")
|
||||
record_voice(true)
|
||||
loopback_player.stream.mix_rate = current_sample_rate
|
||||
loopback_player.play()
|
||||
local_playback = loopback_player.get_stream_playback()
|
||||
multiplayer.peer_disconnected.connect(remove_disconnected_peer)
|
||||
Multiplayer.player_ready.connect(add_joined_peer)
|
||||
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
if not Steamworks.is_initiallized:
|
||||
return
|
||||
check_for_voice_local()
|
||||
|
||||
func add_joined_peer(id): # Fix calling this on yourself
|
||||
var player : Node3D = Multiplayer.playerDict.get(id)
|
||||
var remote_audio_stream_playback = player.get_node_or_null(voicechat_player_path).get_stream_playback()
|
||||
network_playback.set(id, remote_audio_stream_playback)
|
||||
network_voice_buffer.set(id,PackedByteArray())
|
||||
current_sample_rate = Steam.getVoiceOptimalSampleRate()
|
||||
send_sample_rate.rpc_id(id, current_sample_rate)
|
||||
func remove_disconnected_peer(id):
|
||||
network_playback.erase(id)
|
||||
network_voice_buffer.erase(id)
|
||||
|
||||
func check_for_voice_local() -> void:
|
||||
var available_voice: Dictionary = Steam.getAvailableVoice()
|
||||
if !available_voice:
|
||||
return
|
||||
# Seems there is voice data
|
||||
if available_voice['result'] == Steam.VOICE_RESULT_OK and available_voice['buffer'] > 0:
|
||||
# Valve's getVoice uses 1024 but GodotSteam's is set at 8192?
|
||||
# Our sizes might be way off; internal GodotSteam notes that Valve suggests 8kb
|
||||
# However, this is not mentioned in the header nor the SpaceWar example but -is- in Valve's docs which are usually wrong
|
||||
var voice_data: Dictionary = Steam.getVoice()
|
||||
if voice_data['result'] == Steam.VOICE_RESULT_OK and voice_data['written']:
|
||||
#print("[VoiceChat] Voice message has data: %s / %s" % [voice_data['result'], voice_data['written']])
|
||||
|
||||
# Here we can pass this voice data off on the network
|
||||
#TODO: Only execute if multiplayer connected
|
||||
get_sample_rate()
|
||||
send_voice.rpc(voice_data['buffer'])
|
||||
|
||||
# If loopback is enable, play it back at this point
|
||||
if has_loopback:
|
||||
# Our sample rate function above without toggling
|
||||
process_voice_data(voice_data['buffer'], 1)
|
||||
|
||||
@rpc("any_peer","call_remote","unreliable")
|
||||
func send_voice(voice_buffer : PackedByteArray):
|
||||
var sender_id : int = multiplayer.get_remote_sender_id()
|
||||
if not network_playback.has(sender_id):
|
||||
push_error("[VoiceChat] Received audio data, but there is no AudioStreamPlayer available for that user. Emitter: " + str(sender_id))
|
||||
return
|
||||
if not network_voice_buffer.has(sender_id):
|
||||
push_error("[VoiceChat] Received audio data without allocated voice buffer for that user. Emitter: " + str(sender_id))
|
||||
return
|
||||
var local_peer_buffer : PackedByteArray = network_voice_buffer.get(sender_id)
|
||||
if local_peer_buffer.size() >= max_buffer_size:
|
||||
push_error("[VoiceChat] AudioBuffer exeeding size limit. Emitter: " + str(sender_id))
|
||||
process_voice_data(voice_buffer, sender_id)
|
||||
|
||||
@rpc("any_peer","call_remote","reliable")
|
||||
func send_sample_rate(sample_rate : int):
|
||||
var sender_id : int = multiplayer.get_remote_sender_id()
|
||||
if sample_rate < sample_rate_min || sample_rate > sample_rate_max:
|
||||
push_warning("[VoiceChat] Received invalid sample rate for peer. Emitter: " + str(sender_id))
|
||||
return
|
||||
if not network_playback.has(sender_id):
|
||||
push_warning("[VoiceChat] Received sample rate for invalid peer. Emitter: " + str(sender_id)) # Race condition?
|
||||
return
|
||||
if not Multiplayer.playerDict.has(sender_id):
|
||||
push_error("[VoiceChat] Player exists in VoiceChat variables, but not playerDict??? Emitter: " + str(sender_id))
|
||||
return
|
||||
if not Multiplayer.playerDict.has(sender_id): return
|
||||
var player : Node3D = Multiplayer.playerDict.get(sender_id)
|
||||
if not player.has_node(voicechat_player_path): return
|
||||
player.get_node(voicechat_player_path).stream.mix_rate = sample_rate # Fix this (ref: process_voice_data TODO:_1
|
||||
network_playback.get(sender_id).clear_buffer()
|
||||
network_voice_buffer.get(sender_id).clear()
|
||||
|
||||
func get_sample_rate() -> void:
|
||||
current_sample_rate = Steam.getVoiceOptimalSampleRate()
|
||||
if loopback_player.stream.mix_rate != current_sample_rate:
|
||||
send_sample_rate.rpc(current_sample_rate)
|
||||
loopback_player.stream.mix_rate = current_sample_rate
|
||||
print("[VoiceChat] Changed own sample rate to: " + str(current_sample_rate))
|
||||
|
||||
func process_voice_data(voice_data: PackedByteArray, voice_source: int) -> void:
|
||||
#TODO:_1 Fix this with a mix rate dict
|
||||
var decompressed_voice : Dictionary
|
||||
if voice_source == 0:
|
||||
decompressed_voice = Steam.decompressVoice(voice_data, current_sample_rate)
|
||||
elif Multiplayer.playerDict.has(voice_source):
|
||||
var player : Node3D = Multiplayer.playerDict.get(voice_source)
|
||||
if not player.has_node(voicechat_player_path):
|
||||
push_error("[VoiceChat] Player %s doesn't have a VoiceChat node", voice_source)
|
||||
return
|
||||
var mix_rate = player.get_node_or_null(voicechat_player_path).stream.mix_rate
|
||||
assert(mix_rate >= sample_rate_min and mix_rate <= sample_rate_max)
|
||||
decompressed_voice = Steam.decompressVoice(voice_data, mix_rate)
|
||||
else:
|
||||
push_error("[VoiceChat] Received voice data for non existing player")
|
||||
return
|
||||
if decompressed_voice['result'] == Steam.VOICE_RESULT_OK and decompressed_voice['size'] > 0:
|
||||
|
||||
if voice_source == 0:
|
||||
local_voice_buffer = decompressed_voice['uncompressed']
|
||||
local_voice_buffer.resize(decompressed_voice['size'])
|
||||
|
||||
# We now iterate through the local_voice_buffer and push the samples to the audio generator
|
||||
for i: int in local_playback.get_frames_available():
|
||||
if local_voice_buffer.size() == 0: break
|
||||
# Steam's audio data is represented as 16-bit single channel PCM audio, so we need to convert it to amplitudes
|
||||
# Combine the low and high bits to get full 16-bit value
|
||||
var raw_value: int = local_voice_buffer[0] | (local_voice_buffer[1] << 8)
|
||||
# Make it a 16-bit signed integer
|
||||
raw_value = (raw_value + 32768) & 0xffff
|
||||
# Convert the 16-bit integer to a float on from -1 to 1
|
||||
var amplitude: float = float(raw_value - 32768) / 32768.0
|
||||
|
||||
# push_frame() takes a Vector2. The x represents the left channel and the y represents the right channel
|
||||
local_playback.push_frame(Vector2(amplitude, amplitude))
|
||||
|
||||
# Delete the used samples
|
||||
local_voice_buffer.remove_at(0)
|
||||
local_voice_buffer.remove_at(0)
|
||||
else:
|
||||
#TODO: Better naming
|
||||
#TODO: Better explanation for 16-bit conversions
|
||||
var peer_voice_buffer : PackedByteArray = network_voice_buffer.get(voice_source)
|
||||
peer_voice_buffer = decompressed_voice['uncompressed']
|
||||
peer_voice_buffer.resize(decompressed_voice['size'])
|
||||
|
||||
var peer_playback : AudioStreamGeneratorPlayback = network_playback.get(voice_source)
|
||||
for i: int in peer_playback.get_frames_available():
|
||||
if peer_voice_buffer.size() == 0: break
|
||||
var raw_value: int = peer_voice_buffer[0] | (peer_voice_buffer[1] << 8)
|
||||
# Make it a 16-bit signed integer
|
||||
raw_value = (raw_value + 32768) & 0xffff
|
||||
# Convert the 16-bit integer to a float on from -1 to 1
|
||||
var amplitude: float = float(raw_value - 32768) / 32768.0
|
||||
|
||||
# push_frame() takes a Vector2. The x represents the left channel and the y represents the right channel
|
||||
peer_playback.push_frame(Vector2(amplitude, amplitude))
|
||||
|
||||
# Delete the used samples
|
||||
peer_voice_buffer.remove_at(0)
|
||||
peer_voice_buffer.remove_at(0)
|
||||
|
||||
func record_voice(is_recording: bool) -> void:
|
||||
# If talking, suppress all other audio or voice comms from the Steam UI
|
||||
Steam.setInGameVoiceSpeaking(Steamworks.steam_id, is_recording)
|
||||
|
||||
if is_recording:
|
||||
Steam.startVoiceRecording()
|
||||
else:
|
||||
Steam.stopVoiceRecording()
|
||||
1
script/audioManager.gd.uid
Normal file
1
script/audioManager.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://hd16egrl0bjr
|
||||
73
script/featuremanager.gd
Normal file
73
script/featuremanager.gd
Normal file
@@ -0,0 +1,73 @@
|
||||
extends Node
|
||||
|
||||
@onready var syncedFeatures: ConfigFile = ConfigFile.new()
|
||||
@onready var settingsmenu = $/root/Main/Settingsmenu/VBoxContainer/MarginContainer2/HBoxContainer/VBoxContainer
|
||||
@onready var config : ConfigFile = ConfigFile.new()
|
||||
@export var debug : bool = false
|
||||
|
||||
func _ready() -> void:
|
||||
var ms = MultiplayerSynchronizer.new()
|
||||
var spg = SceneReplicationConfig.new()
|
||||
var ppath = name + ":syncedFeatures"
|
||||
spg.add_property(ppath)
|
||||
ms.name = "ConfigSynchronizer"
|
||||
ms.replication_config = spg
|
||||
$/root.add_child.call_deferred(ms)
|
||||
loadConfig()
|
||||
update_menu()
|
||||
|
||||
func update_menu():
|
||||
for feature in config.get_sections():
|
||||
var container = HBoxContainer.new()
|
||||
container.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
container.name = feature
|
||||
var label = Label.new()
|
||||
label.text = feature
|
||||
container.add_child(label)
|
||||
var control : Control
|
||||
match config.get_value(feature,"mode","_"):
|
||||
"check":
|
||||
control = CheckButton.new()
|
||||
"color:":
|
||||
control = ColorPickerButton.new()
|
||||
"text":
|
||||
control = LineEdit.new()
|
||||
"menu":
|
||||
control = OptionButton.new()
|
||||
"button":
|
||||
control = Button.new()
|
||||
_:
|
||||
control = Button.new()
|
||||
container.add_child(control)
|
||||
settingsmenu.add_child(container)
|
||||
func loadConfig():
|
||||
var err : Error = config.load("user://config.cfg") if not debug else config.load("res://defaultconfig.cfg")
|
||||
match err:
|
||||
OK:
|
||||
print("Config loaded.")
|
||||
return
|
||||
ERR_FILE_NOT_FOUND:
|
||||
push_error("Config not found. Loading default config.")
|
||||
_:
|
||||
push_error("Failed to load config: error " + str(err))
|
||||
var err2 : Error = config.load("res://defaultconfig.cfg")
|
||||
match err2:
|
||||
OK:
|
||||
push_warning("Default config loaded successfully.")
|
||||
ERR_PARSE_ERROR:
|
||||
push_error("Invalid default config")
|
||||
return
|
||||
_:
|
||||
push_error("Yay a bug " + str(err2))
|
||||
return
|
||||
if ResourceLoader.exists("user://config.cfg"):
|
||||
return
|
||||
var err3 : Error = config.save("user://config.cfg")
|
||||
match err3:
|
||||
OK:
|
||||
print("Saved new config file")
|
||||
ERR_FILE_NO_PERMISSION:
|
||||
push_error("No permission to save new config file.")
|
||||
_:
|
||||
push_error("Could not save new config file: " + str(err3))
|
||||
return
|
||||
1
script/featuremanager.gd.uid
Normal file
1
script/featuremanager.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://4r044bvpv02o
|
||||
17
script/interactBox.gd
Normal file
17
script/interactBox.gd
Normal file
@@ -0,0 +1,17 @@
|
||||
extends Area3D
|
||||
class_name InteractBox
|
||||
|
||||
signal interactedWith(playerRef: PlayerCharacter)
|
||||
@export var object: Node #Logic for how the interaction works, look for the ButtonLogicToggle, or ButtonLogicImpulse nodes
|
||||
@export var type: String = "default"
|
||||
var playerRef: PlayerCharacter
|
||||
|
||||
func _ready() -> void:
|
||||
set_collision_layer_value(6,true) #Enables Interaction colision layer
|
||||
set_collision_layer_value(1,false) #Disables Default collision layer
|
||||
set_collision_mask_value(1,false) #Disables Default collision mask
|
||||
monitoring = false
|
||||
|
||||
func interact() -> void:
|
||||
interactedWith.emit(playerRef)
|
||||
playerRef = null
|
||||
1
script/interactBox.gd.uid
Normal file
1
script/interactBox.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://ymaax1x5fos3
|
||||
257
script/main.gd
Normal file
257
script/main.gd
Normal file
@@ -0,0 +1,257 @@
|
||||
extends Control
|
||||
class_name Main
|
||||
|
||||
@onready var start_btn : Button = $Mainmenu/Menu/MarginContainer/VBoxContainer/HBoxContainer4/VBoxContainer3/Start
|
||||
@onready var disconnect_btn : Button = $Pausemenu/Menu/MarginContainer/VBoxCurrentLobby/Disconnect
|
||||
@onready var name_edit : = $Mainmenu/Menu/MarginContainer/VBoxContainer/HBoxContainer4/VBoxContainer2/NameEdit
|
||||
@onready var disconnectDialog = $Dialogs/DisconnectDialog
|
||||
|
||||
@onready var pausemenu: Control = $Pausemenu
|
||||
@onready var settingsmenu: Control = $Settingsmenu
|
||||
@onready var mainmenu: Control = $Mainmenu
|
||||
@onready var hud: Control = $Hud
|
||||
@onready var mapScreen: MapScreen = $MapScreen
|
||||
@onready var missionEndScreen: MissionEndScreen = $MissionEndScreen
|
||||
@onready var loadingScreen: Control = $LoadingScreen
|
||||
|
||||
@onready var mapsParent: Node3D = $Maps
|
||||
@onready var playersParent: Node3D = $Players
|
||||
|
||||
var peer = WebSocketMultiplayerPeer.new()
|
||||
var lobby: String = "res://Maps/Lobby/Lobby.tscn"
|
||||
|
||||
var player: PackedScene = preload("res://actors/Player/player_character.tscn")
|
||||
|
||||
@onready var currentMenu: Control = $Mainmenu
|
||||
var settingsPressed: bool = false #Flag for when Settings button is pressed, handled in process by Menu handeling function
|
||||
|
||||
var displayMissionEndScreen: bool = false #Display Mission end screen while true
|
||||
|
||||
var displayLoadingScreen: bool = false
|
||||
|
||||
func _init():
|
||||
peer.supported_protocols = ["ludus"]
|
||||
Steamworks.initialize()
|
||||
|
||||
func _ready():
|
||||
await Multiplayer.noray_connected
|
||||
multiplayer.peer_connected.connect(peer_connected)
|
||||
multiplayer.peer_disconnected.connect(peer_disconnected)
|
||||
multiplayer.server_disconnected.connect(close_network)
|
||||
multiplayer.connection_failed.connect(close_network)
|
||||
multiplayer.connected_to_server.connect(connected)
|
||||
# Set the player name according to the system username. Fallback to the path.
|
||||
if Steamworks.is_initiallized:
|
||||
get_tree().auto_accept_quit = false
|
||||
Steamworks.create_lobby()
|
||||
name_edit.text = Steam.getPersonaName()
|
||||
elif false: #TODO: Set text to saved value
|
||||
name_edit.text = ""
|
||||
disableMultiplayer()
|
||||
else:
|
||||
name_edit.text = "Spacebots Player"
|
||||
disableMultiplayer()
|
||||
|
||||
func _process(_delta: float):
|
||||
|
||||
#Does all switching between Menus
|
||||
handleMenus()
|
||||
|
||||
|
||||
|
||||
func changeMenu(changeTo: Control) -> void:
|
||||
if currentMenu == changeTo: return
|
||||
var thisPlayer := Multiplayer.thisPlayer
|
||||
|
||||
if thisPlayer:
|
||||
if changeTo == hud or changeTo == missionEndScreen:
|
||||
thisPlayer.currentControlState = thisPlayer.controls.DEFAULT
|
||||
else:
|
||||
thisPlayer.currentControlState = thisPlayer.controls.STANDARD_MINIGAME
|
||||
|
||||
currentMenu.hide()
|
||||
changeTo.show()
|
||||
|
||||
changeTo.grab_focus.call_deferred()
|
||||
|
||||
currentMenu = changeTo
|
||||
|
||||
func handleMenus() -> void: #This function returns after an Input is handled, ensuring one menu action per frame and avoiding conflicts
|
||||
if !playersParent.get_child_count() > 0: return
|
||||
|
||||
#Flags for which Inputs are pressed
|
||||
var pausePressed: bool = Input.is_action_just_pressed("pause")
|
||||
var leaveMinigamePressed: bool = Input.is_action_just_pressed("leaveMinigame")
|
||||
var mapPressed: bool = Input.is_action_just_pressed("map")
|
||||
|
||||
if displayLoadingScreen:
|
||||
if currentMenu != loadingScreen:
|
||||
changeMenu(loadingScreen)
|
||||
|
||||
return
|
||||
|
||||
if displayMissionEndScreen:
|
||||
if currentMenu != missionEndScreen:
|
||||
changeMenu(missionEndScreen)
|
||||
|
||||
return
|
||||
|
||||
|
||||
if mapPressed:
|
||||
if Minigames.minigameActive: Minigames.endMinigame(false)
|
||||
if currentMenu != mapScreen:
|
||||
changeMenu(mapScreen)
|
||||
else:
|
||||
changeMenu(hud)
|
||||
|
||||
return
|
||||
|
||||
if (leaveMinigamePressed or pausePressed) and Minigames.minigameActive:
|
||||
Minigames.endMinigame(false)
|
||||
|
||||
return
|
||||
|
||||
if settingsPressed:
|
||||
if currentMenu != settingsmenu:
|
||||
changeMenu(settingsmenu)
|
||||
else:
|
||||
changeMenu(pausemenu)
|
||||
settingsPressed = false
|
||||
|
||||
return
|
||||
|
||||
if pausePressed:
|
||||
if currentMenu == hud:
|
||||
changeMenu(pausemenu)
|
||||
else:
|
||||
changeMenu(hud)
|
||||
|
||||
return
|
||||
|
||||
func disableMultiplayer() -> void:
|
||||
$/root/Main/Mainmenu/Menu/MarginContainer/VBoxContainer/HBoxContainer/VBoxMultiplayerDisabled.show()
|
||||
$/root/Main/Mainmenu/Menu/MarginContainer/VBoxContainer/HBoxContainer/VBoxLobbylist.hide()
|
||||
|
||||
func start_game():
|
||||
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
|
||||
mainmenu.hide()
|
||||
start_btn.disabled = true
|
||||
disconnect_btn.disabled = false
|
||||
hud.show()
|
||||
|
||||
@rpc("authority","call_local","reliable")
|
||||
func changeMap(newMap: String, mapSeed: int = 0) -> void:
|
||||
if !(load(newMap).instantiate() is MapLogic):
|
||||
push_error("newMap: String is not a map scene")
|
||||
return
|
||||
|
||||
var map : MapLogic = load(newMap).instantiate()
|
||||
|
||||
if newMap == "res://test/spaceship_test.tscn":
|
||||
map.setSeed(hash(mapSeed))
|
||||
|
||||
if mapsParent.get_child_count() > 0:
|
||||
if Multiplayer.getCurrentMapLogic().is_connected(StringName("missionLost"),missionLost):
|
||||
Multiplayer.getCurrentMapLogic().disconnect(StringName("missionLost"),missionLost)
|
||||
mapsParent.get_child(0).queue_free()
|
||||
|
||||
mapsParent.add_child(map)
|
||||
initiatePlayerPosition(map.playerStartPos)
|
||||
|
||||
Multiplayer.setCurrentMapLogic(map)
|
||||
map.missionLost.connect(missionLost)
|
||||
|
||||
func initiatePlayerPosition(pos: Vector3) -> void:
|
||||
for p in Multiplayer.playerDict.values():
|
||||
if p.is_multiplayer_authority():
|
||||
p.global_position = pos
|
||||
|
||||
func missionLost() -> void:
|
||||
changeMap(lobby)
|
||||
|
||||
func stop_game():
|
||||
disconnect_btn.disabled = true
|
||||
mainmenu.show()
|
||||
pausemenu.hide()
|
||||
hud.hide()
|
||||
Input.mouse_mode = Input.MOUSE_MODE_CONFINED
|
||||
#Steamworks.stop()
|
||||
|
||||
var currentMaps = mapsParent.get_children()
|
||||
for child in currentMaps:
|
||||
child.queue_free()
|
||||
|
||||
var players = playersParent.get_children()
|
||||
for child in players:
|
||||
child.set_process(false)
|
||||
child.queue_free()
|
||||
await get_tree().process_frame
|
||||
start_btn.disabled = false
|
||||
|
||||
|
||||
func close_network():
|
||||
peer.close()
|
||||
stop_game()
|
||||
disconnectDialog.popup_centered()
|
||||
disconnectDialog.get_ok_button().grab_focus()
|
||||
multiplayer.multiplayer_peer = null
|
||||
Multiplayer.currentMapLogic = null
|
||||
Multiplayer.playerDict = {}
|
||||
Multiplayer.alivePlayerDict = {}
|
||||
Multiplayer.is_host = false
|
||||
Steamworks.lobby_id = 0
|
||||
Steamworks.lobby_members = []
|
||||
Steamworks.lobby_members_max = 5
|
||||
Steamworks.steam_id = 0
|
||||
Steamworks.steam_username = ""
|
||||
|
||||
|
||||
func connected():
|
||||
if Multiplayer.is_host == false:
|
||||
add_player.rpc_id(1, multiplayer.get_unique_id())
|
||||
|
||||
|
||||
func peer_connected(_id):
|
||||
pass
|
||||
#Steamworks.on_peer_add(id)
|
||||
|
||||
|
||||
func peer_disconnected(id):
|
||||
if Multiplayer.is_host:
|
||||
remove_player(id)
|
||||
|
||||
func on_server_disconnected():
|
||||
on_Disconnect_pressed()
|
||||
|
||||
func on_Start_pressed():
|
||||
Multiplayer.host()
|
||||
start_game()
|
||||
changeMap(lobby)
|
||||
changeMenu(hud)
|
||||
add_player(multiplayer.get_unique_id())
|
||||
|
||||
func on_Disconnect_pressed():
|
||||
if Steamworks.lobby_members.size() > 1:
|
||||
Steam.leaveLobby(Steamworks.lobby_id)
|
||||
close_network()
|
||||
|
||||
func on_settings_pressed():
|
||||
settingsPressed = true
|
||||
|
||||
func on_Connect(norayid: String):
|
||||
start_btn.disabled = true
|
||||
disconnect_btn.disabled = false
|
||||
start_game()
|
||||
changeMap(lobby)
|
||||
Multiplayer.join(norayid)
|
||||
|
||||
@rpc("any_peer")
|
||||
func add_player(id):
|
||||
var player_instance: PlayerCharacter = player.instantiate()
|
||||
player_instance.name = str(id)
|
||||
playersParent.add_child(player_instance)
|
||||
|
||||
@rpc("any_peer")
|
||||
func remove_player(id):
|
||||
if playersParent.get_node(str(id)):
|
||||
playersParent.get_node(str(id)).queue_free()
|
||||
1
script/main.gd.uid
Normal file
1
script/main.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://b4avd5n3wv18p
|
||||
14
script/mainmenu.gd
Normal file
14
script/mainmenu.gd
Normal file
@@ -0,0 +1,14 @@
|
||||
extends Control
|
||||
|
||||
@onready var debugbtn : Button = $/root/Main/Mainmenu/Menu/MarginContainer/VBoxContainer/HBoxContainer/VBoxLobbylist/RefreshLobbies
|
||||
@onready var main : Control = $/root/Main
|
||||
func on_start_pressed() -> void:
|
||||
main.on_Start_pressed()
|
||||
|
||||
func on_lobby_list_item_activated(index: int) -> void:
|
||||
Steamworks.leave_lobby()
|
||||
var lobby_id = Steamworks.lobby_index_list.get(index)
|
||||
Steamworks.join_lobby(lobby_id)
|
||||
|
||||
func on_refresh_lobbies_pressed() -> void:
|
||||
Steamworks.render_global_lobbies()
|
||||
1
script/mainmenu.gd.uid
Normal file
1
script/mainmenu.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dfqkj3vcm3a84
|
||||
59
script/map_screen.gd
Normal file
59
script/map_screen.gd
Normal file
@@ -0,0 +1,59 @@
|
||||
extends Control
|
||||
class_name MapScreen
|
||||
|
||||
@onready var map: TextureRect = $TextureRect
|
||||
@onready var playerIndicator: ColorRect = $PlayerIndicator
|
||||
@onready var taskListContainer: VBoxContainer = $TaskList
|
||||
@onready var taskLabelSettings: LabelSettings = preload("res://test/TaskListLabelSettingstest.tres")
|
||||
|
||||
var mapImmage: Image
|
||||
var playerCharacter: PlayerCharacter
|
||||
var mapDimensions: Vector2 = Vector2(0,0)
|
||||
var trackPlayer: bool = false
|
||||
|
||||
var taskList: Array[MissionTask]
|
||||
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
#Update Player Pos on map
|
||||
|
||||
if trackPlayer and playerCharacter:
|
||||
playerIndicator.position = Vector2(playerCharacter.position.x, playerCharacter.position.z) * map.size/mapDimensions + Vector2(map.size.x/2 + map.position.x,map.size.y/2 + map.position.y) - playerIndicator.size/2
|
||||
|
||||
func generateMap(grid: Array[Array]) -> void: #Seccond Array contains gridCells
|
||||
mapImmage = Image.create_empty(grid.size(),grid[0].size(),false,Image.FORMAT_RGB8)
|
||||
|
||||
for x in grid.size():
|
||||
for y in grid[x].size():
|
||||
if grid[x][y].biomeConnection:
|
||||
mapImmage.set_pixel(x,y,Color.DARK_GREEN)
|
||||
elif grid[x][y].spaceTaken:
|
||||
mapImmage.set_pixel(x,y,Color.GREEN)
|
||||
else:
|
||||
mapImmage.set_pixel(x,y,Color.DIM_GRAY)
|
||||
|
||||
map.texture = ImageTexture.create_from_image(mapImmage)
|
||||
|
||||
mapDimensions = Vector2(grid.size(),grid[0].size())
|
||||
|
||||
|
||||
if !playerCharacter:
|
||||
playerCharacter = Multiplayer.thisPlayer
|
||||
|
||||
trackPlayer = true
|
||||
|
||||
func addTask(task: MissionTask) -> void:
|
||||
taskList.push_back(task)
|
||||
|
||||
var label := Label.new()
|
||||
label.name = task.taskName
|
||||
label.text = task.description
|
||||
label.label_settings = taskLabelSettings
|
||||
|
||||
taskListContainer.add_child(label)
|
||||
task.taskLabel = label
|
||||
|
||||
func completeTask(task: MissionTask) -> void:
|
||||
if taskList.has(task):
|
||||
task.taskLabel.queue_free()
|
||||
taskList.erase(task)
|
||||
1
script/map_screen.gd.uid
Normal file
1
script/map_screen.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bshnb8sg3aqv6
|
||||
36
script/minigames.gd
Normal file
36
script/minigames.gd
Normal file
@@ -0,0 +1,36 @@
|
||||
extends Control
|
||||
|
||||
#TODO: After Minigame is completed next Pausemenu only opens after pressing twice
|
||||
|
||||
var minigameActive: bool = false
|
||||
signal minigameCompleted
|
||||
var currentInitiator: MinigameInitiator
|
||||
|
||||
func _ready() -> void:
|
||||
pass
|
||||
|
||||
#func _process(_delta: float) -> void:
|
||||
#if Input.is_action_just_pressed("leaveMinigame"): endMinigame()
|
||||
|
||||
func spawnMinigame(minigameName: String, initiator: MinigameInitiator) -> void:
|
||||
if minigameActive: return
|
||||
|
||||
match minigameName:
|
||||
"wires":
|
||||
add_child(preload("res://Minigames/Minigames/Wires.tscn").instantiate())
|
||||
|
||||
minigameActive = true
|
||||
currentInitiator = initiator
|
||||
|
||||
|
||||
func endMinigame(outcome: bool) -> void:
|
||||
if !minigameActive: return
|
||||
|
||||
if outcome:
|
||||
currentInitiator.minigameCompleted = true
|
||||
minigameCompleted.emit()
|
||||
else:
|
||||
get_child(0).queue_free()
|
||||
minigameActive = false
|
||||
currentInitiator = null
|
||||
Multiplayer.thisPlayer.currentControlState = 0
|
||||
1
script/minigames.gd.uid
Normal file
1
script/minigames.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://co70l80bjck4u
|
||||
4
script/mission_end_screen.gd
Normal file
4
script/mission_end_screen.gd
Normal file
@@ -0,0 +1,4 @@
|
||||
extends Control
|
||||
class_name MissionEndScreen
|
||||
|
||||
@onready var label: Label = $Label
|
||||
1
script/mission_end_screen.gd.uid
Normal file
1
script/mission_end_screen.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://c6sryrvdtdvk4
|
||||
125
script/multiplayer.gd
Normal file
125
script/multiplayer.gd
Normal file
@@ -0,0 +1,125 @@
|
||||
extends Node
|
||||
|
||||
signal noray_connected
|
||||
signal player_ready(id : int)
|
||||
const NORAY_ADDRESS = "tomfol.io"
|
||||
const NORAY_PORT = 8890
|
||||
|
||||
var is_host = false
|
||||
var external_oid = ""
|
||||
var debug = false
|
||||
|
||||
var playerDict: Dictionary[int,PlayerCharacter]
|
||||
var alivePlayerDict: Dictionary[int,PlayerCharacter]
|
||||
var currentMapLogic: MapLogic
|
||||
|
||||
var thisPlayer: PlayerCharacter #Player Character playing on this machiene, this value is obviously different for every player
|
||||
|
||||
@onready var errordialog = $/root/Main/Dialogs/ErrorDialog
|
||||
@onready var start_btn : Button = $/root/Main/Mainmenu/Menu/MarginContainer/VBoxContainer/HBoxContainer4/VBoxContainer3/Start
|
||||
@onready var main : Main = $/root/Main
|
||||
|
||||
func _ready():
|
||||
Noray.on_connect_to_host.connect(on_noray_connected)
|
||||
Noray.on_connect_nat.connect(handle_nat_connection)
|
||||
#Noray.on_connect_relay.connect(handle_relay_connection)
|
||||
|
||||
Noray.connect_to_host(NORAY_ADDRESS, NORAY_PORT)
|
||||
player_ready.connect(peer_connected)
|
||||
multiplayer.peer_disconnected.connect(peer_disconnected)
|
||||
func getCurrentMapLogic() -> MapLogic:
|
||||
return currentMapLogic
|
||||
func setCurrentMapLogic(toMap: MapLogic) -> void:
|
||||
currentMapLogic = toMap
|
||||
|
||||
func peer_connected(id: int) -> void:
|
||||
if !get_node("/root/Main/Players").get_child_count(): return
|
||||
|
||||
playerDict.set(id,get_node("/root/Main/Players/" + str(id)))
|
||||
alivePlayerDict.set(id,get_node("/root/Main/Players/" + str(id)))
|
||||
if !playerDict.get(id): playerDict.erase(id)
|
||||
if !alivePlayerDict.get(id): alivePlayerDict.erase(id)
|
||||
|
||||
func peer_disconnected(id: int) -> void:
|
||||
playerDict.erase(id)
|
||||
alivePlayerDict.erase(id)
|
||||
|
||||
|
||||
func on_noray_connected():
|
||||
print("Connected to Noray server")
|
||||
|
||||
Noray.register_host()
|
||||
await Noray.on_pid
|
||||
await Noray.register_remote()
|
||||
start_btn.disabled = false
|
||||
noray_connected.emit()
|
||||
|
||||
func host():
|
||||
var peer = ENetMultiplayerPeer.new()
|
||||
var error = OK
|
||||
if debug:
|
||||
error = peer.create_server(1069)
|
||||
else:
|
||||
error = peer.create_server(Noray.local_port)
|
||||
if error:
|
||||
errordialog.title = "Error"
|
||||
errordialog.dialog_text = "Failed to create Server: " + str(error_string(error) + " (" + str(error) + ")")
|
||||
errordialog.popup_centered()
|
||||
errordialog.get_ok_button().grab_focus()
|
||||
main.close_network()
|
||||
else:
|
||||
multiplayer.multiplayer_peer = peer
|
||||
is_host = true
|
||||
|
||||
func join(oid: String):
|
||||
if debug:
|
||||
var peer = ENetMultiplayerPeer.new()
|
||||
var error = peer.create_client("localhost", 1069)
|
||||
print("Join: " + error_string(error) + " " + str(error))
|
||||
multiplayer.multiplayer_peer = peer
|
||||
return
|
||||
Noray.connect_nat(oid)
|
||||
external_oid = oid
|
||||
|
||||
func handle_nat_connection(address, port):
|
||||
var err = await connect_to_server(address, port)
|
||||
|
||||
if err != OK && !is_host:
|
||||
print("NAT failed, using relay")
|
||||
err = Noray.connect_relay(external_oid)
|
||||
|
||||
return err
|
||||
|
||||
func handle_relay_connection(address, port):
|
||||
return await connect_to_server(address, port)
|
||||
|
||||
func connect_to_server(address, port):
|
||||
var err = OK
|
||||
if !is_host:
|
||||
var udp = PacketPeerUDP.new()
|
||||
udp.bind(Noray.local_port)
|
||||
udp.set_dest_address(address, port)
|
||||
|
||||
err = await PacketHandshake.over_packet_peer(udp)
|
||||
udp.close()
|
||||
|
||||
if err != OK:
|
||||
if err != ERR_BUSY:
|
||||
print("Handshake failed")
|
||||
return err
|
||||
else:
|
||||
print("Handshake success")
|
||||
|
||||
var peer = ENetMultiplayerPeer.new()
|
||||
err = peer.create_client(address, port, 0, 0, 0, Noray.local_port)
|
||||
|
||||
if err != OK:
|
||||
return err
|
||||
|
||||
multiplayer.multiplayer_peer = peer
|
||||
|
||||
return OK
|
||||
else:
|
||||
err = await PacketHandshake.over_enet(multiplayer.multiplayer_peer.host, address, port)
|
||||
|
||||
return err
|
||||
1
script/multiplayer.gd.uid
Normal file
1
script/multiplayer.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://77q1pjrfpua6
|
||||
31
script/objectSpawner.gd
Normal file
31
script/objectSpawner.gd
Normal file
@@ -0,0 +1,31 @@
|
||||
extends Node3D
|
||||
#class_name ObjectSpawner
|
||||
|
||||
@export var Objects: Array[RandomObject]
|
||||
@export var Parent: Node
|
||||
var weightArray: PackedFloat32Array
|
||||
var rng = RandomNumberGenerator.new()
|
||||
|
||||
|
||||
func _ready():
|
||||
if Objects.is_empty(): return
|
||||
|
||||
var spaceship = get_node("/root/Main/Maps/Spaceship")
|
||||
for obj in Objects: #Init weight array
|
||||
weightArray.push_back(obj.probability)
|
||||
|
||||
var objectReference = load(Objects[rng.rand_weighted(weightArray)].dir) #Get random Object depending on weights
|
||||
var ObjectInstance = objectReference.instantiate()
|
||||
|
||||
if Parent:
|
||||
Parent.call_deferred("add_child",ObjectInstance) #Adds Object instance
|
||||
elif spaceship:
|
||||
spaceship.call_deferred("add_child",ObjectInstance)
|
||||
else:
|
||||
push_error("Object Spawner failed to spawn object because of missing parent node")
|
||||
|
||||
ObjectInstance.rotation = self.global_rotation
|
||||
ObjectInstance.position = self.global_position
|
||||
|
||||
self.queue_free()
|
||||
|
||||
1
script/objectSpawner.gd.uid
Normal file
1
script/objectSpawner.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dfqpquon420gl
|
||||
89
script/pathfindingGridLoad.gd
Normal file
89
script/pathfindingGridLoad.gd
Normal file
@@ -0,0 +1,89 @@
|
||||
extends Node3D
|
||||
class_name PathfindingGridLoader
|
||||
|
||||
var loading: bool = false # when this is true the grid starts loading
|
||||
var loading_done: bool = false # when the grid is loaded, this becomes true
|
||||
|
||||
@export var height: float= 0.2 ##Choose a height that is just above the floor
|
||||
@export var lengthX: int = 50 ##How far the grid generates in the x direction, generates as a rectangle
|
||||
@export var lengthZ: int = 50 ##How far the grid generates in the z direction, generates as a rectangle
|
||||
@export var point_density: float = 1 ##How many points per unit of grid, cannot be = 0
|
||||
@export var minimum_connections_per_point: int = 3
|
||||
@export var wallCollisionLayer: int = 0b100
|
||||
|
||||
var astar: AStar2D = AStar2D.new()
|
||||
|
||||
func _physics_process(_delta: float) -> void:
|
||||
if loading == false: return
|
||||
if loading_done == true: return
|
||||
generatePoints()
|
||||
connectPointsToNeighbors()
|
||||
killPointsWithoutFriends(minimum_connections_per_point)
|
||||
addWeightToPoints()
|
||||
loading = false
|
||||
loading_done = true
|
||||
|
||||
func loadGrid() -> void:
|
||||
loading = true
|
||||
|
||||
func castRay(startPoint:Vector3,endPoint: Vector3,collisionMask:int = 0xFFFFFFFF,hitFromInside: bool = true) -> bool: ##Returns true if the ray collides and false if it doesn't
|
||||
var space_state = get_world_3d().direct_space_state
|
||||
var rayQueryParam = PhysicsRayQueryParameters3D.create(startPoint,endPoint)
|
||||
rayQueryParam.collision_mask = collisionMask
|
||||
rayQueryParam.hit_from_inside = hitFromInside
|
||||
return space_state.intersect_ray(rayQueryParam).size()
|
||||
|
||||
func checkPoint(point: Vector2) -> bool: ## only ever call this from physics process as it uses physics for raycast and may not work on idle callback
|
||||
var floorDetected: bool = castRay(Vector3(point.x,height,point.y),Vector3(point.x,-(height*1.5),point.y))
|
||||
var wallDetected: bool = castRay(Vector3(point.x,height,point.y),Vector3(point.x,-(height*1.5),point.y),wallCollisionLayer) #Walls are on collision layer 3 (0b100)
|
||||
if !wallDetected && floorDetected:
|
||||
return true
|
||||
else:
|
||||
return false
|
||||
|
||||
func getPointsInRadius(origin: Vector2,radius: float, maxPoints: int = 9) -> Array[int]: #Origin point is always index 0 in the array
|
||||
var pointIDs: Array[int]
|
||||
for point in maxPoints:
|
||||
var id = astar.get_closest_point(origin)
|
||||
if (astar.get_point_position(id) - origin).length() <= radius:
|
||||
pointIDs.push_back(id)
|
||||
astar.set_point_disabled(id)
|
||||
for id in pointIDs:
|
||||
astar.set_point_disabled(id,false)
|
||||
return pointIDs
|
||||
|
||||
func connectIfValid(id1: int, id2: int):
|
||||
var point1 := astar.get_point_position(id1)
|
||||
var point2 := astar.get_point_position(id2)
|
||||
|
||||
if !castRay(Vector3(point1.x,height,point1.y),Vector3(point2.x,height,point2.y)):
|
||||
astar.connect_points(id1,id2)
|
||||
|
||||
func generatePoints() -> void:
|
||||
var currentPoint: Vector2
|
||||
var currentID: int = 0
|
||||
for x in lengthX*point_density:
|
||||
for z in lengthZ*point_density:
|
||||
currentPoint = Vector2((x/point_density + self.global_position.x),z/point_density + self.global_position.z)
|
||||
if checkPoint(currentPoint):
|
||||
astar.add_point(currentID,currentPoint)
|
||||
currentID += 1
|
||||
|
||||
func connectPointsToNeighbors() -> void:
|
||||
for id in astar.get_point_ids():
|
||||
var neighborPoints: Array[int]
|
||||
neighborPoints = getPointsInRadius(astar.get_point_position(id),(1/point_density)*1.5)
|
||||
for point in neighborPoints.size()-1:
|
||||
connectIfValid(neighborPoints[0],neighborPoints[point+1])
|
||||
|
||||
func killPointsWithoutFriends(minConnections: int) -> void: ##Really mean and evil and fucked up function
|
||||
var cullPoints: Array[int]
|
||||
for id in astar.get_point_ids():
|
||||
if astar.get_point_connections(id).size() < minConnections:
|
||||
cullPoints.push_back(id)
|
||||
for point in cullPoints:
|
||||
astar.remove_point(point)
|
||||
|
||||
func addWeightToPoints() -> void: #Add weight depending on number of connections
|
||||
for id in astar.get_point_ids():
|
||||
astar.set_point_weight_scale(id,8 - astar.get_point_connections(id).size())
|
||||
1
script/pathfindingGridLoad.gd.uid
Normal file
1
script/pathfindingGridLoad.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cjgxd88k1bntf
|
||||
15
script/pausemenu.gd
Normal file
15
script/pausemenu.gd
Normal file
@@ -0,0 +1,15 @@
|
||||
extends Control
|
||||
|
||||
@onready var main : Main = $/root/Main
|
||||
|
||||
func on_disconnect_pressed() -> void:
|
||||
main.on_Disconnect_pressed()
|
||||
|
||||
func _on_settings_pressed() -> void:
|
||||
main.on_settings_pressed()
|
||||
|
||||
func on_lobby_member_list_item_activated(index: int) -> void:
|
||||
if Steamworks.is_initiallized:
|
||||
print("You clicked on: " + Steam.getFriendPersonaName(Steamworks.member_index_list.get(index)))
|
||||
else:
|
||||
print("You clicked on: index: " + str(index) + " (Steam unavailable)")
|
||||
1
script/pausemenu.gd.uid
Normal file
1
script/pausemenu.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://2niwcxdyq213
|
||||
5
script/randomObject.gd
Normal file
5
script/randomObject.gd
Normal file
@@ -0,0 +1,5 @@
|
||||
extends Node
|
||||
class_name RandomObject
|
||||
|
||||
@export var dir: String
|
||||
@export var probability: float #Value between 0 and 1
|
||||
1
script/randomObject.gd.uid
Normal file
1
script/randomObject.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://d3w6uvg5hmphc
|
||||
22
script/settingsmenu.gd
Normal file
22
script/settingsmenu.gd
Normal file
@@ -0,0 +1,22 @@
|
||||
extends Control
|
||||
|
||||
@onready var main : Main = $/root/Main
|
||||
|
||||
## Previous Code IDC about reading
|
||||
#var settingsmenu : bool = false
|
||||
#
|
||||
#func _process(_delta: float) -> void:
|
||||
#if Input.is_action_just_pressed("settings") and %Pausemenu.visible:
|
||||
#if not %Settingsmenu.visible:
|
||||
#%Settingsmenu.show()
|
||||
#%Settingsmenu.grab_focus()
|
||||
#else:
|
||||
#%Settingsmenu.hide()
|
||||
#%Pausemenu.grab_focus()
|
||||
#settingsmenu = !settingsmenu
|
||||
|
||||
func _on_leave_pressed() -> void:
|
||||
main.on_settings_pressed()
|
||||
|
||||
func _on_quit_pressed() -> void:
|
||||
get_tree().quit()
|
||||
1
script/settingsmenu.gd.uid
Normal file
1
script/settingsmenu.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bsteyp1ndegj
|
||||
4
script/start_ik.gd
Normal file
4
script/start_ik.gd
Normal file
@@ -0,0 +1,4 @@
|
||||
extends SkeletonIK3D
|
||||
|
||||
func _ready() -> void:
|
||||
start()
|
||||
1
script/start_ik.gd.uid
Normal file
1
script/start_ik.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cp822pg0wyna7
|
||||
226
script/steamworks.gd
Normal file
226
script/steamworks.gd
Normal file
@@ -0,0 +1,226 @@
|
||||
extends Control
|
||||
|
||||
@onready var list : ItemList = $/root/Main/Mainmenu/Menu/MarginContainer/VBoxContainer/HBoxContainer/VBoxLobbylist/ItemList
|
||||
@onready var lobby_members_list : ItemList = $/root/Main/Pausemenu/Menu/MarginContainer/VBoxCurrentLobby/LobbyMemberList
|
||||
@onready var profileSprite : Sprite2D = $/root/Main/Mainmenu/Menu/MarginContainer/VBoxContainer/HBoxContainer4/VBoxContainer/ProfileSprite
|
||||
@onready var main : Main = $/root/Main
|
||||
const PACKET_READ_LIMIT: int = 32
|
||||
const app_id: int = 480
|
||||
var is_initiallized: bool = false #Steam initialized successfully
|
||||
|
||||
var lobby_index_list: Dictionary = {} # index -> lobbyid
|
||||
var member_index_list: Dictionary = {} # index -> steam_id
|
||||
var lobby_data
|
||||
var lobby_id: int = 0
|
||||
var lobby_members: Array = []
|
||||
var lobby_members_max: int = 5
|
||||
var steam_id: int = 0
|
||||
var steam_username: String = ""
|
||||
|
||||
func initialize() -> void:
|
||||
var initialize_response: Dictionary = Steam.steamInitEx(false, Steamworks.app_id)
|
||||
if initialize_response["status"] != OK:
|
||||
match initialize_response["status"]:
|
||||
1:
|
||||
push_error("[Steam] Initialization failed: Error")
|
||||
2:
|
||||
push_error("[Steam] Initialization failed: Can't connect to steam.")
|
||||
3:
|
||||
push_error("[Steam] Initialization failed: Steam client out of date.")
|
||||
return
|
||||
print("[Steam] Initialized successfully")
|
||||
steam_id = Steam.getSteamID()
|
||||
steam_username = Steam.getPersonaName()
|
||||
#Load user avatar
|
||||
Steam.getPlayerAvatar(Steam.AVATAR_SMALL,Steam.getSteamID())
|
||||
Steam.avatar_loaded.connect(steam_avatar_loaded)
|
||||
|
||||
Steam.join_requested.connect(on_lobby_join_requested)
|
||||
Steam.lobby_chat_update.connect(on_lobby_chat_update)
|
||||
Steam.lobby_created.connect(on_lobby_created)
|
||||
# Steam.lobby_data_update.connect(on_lobby_data_update)
|
||||
#Steam.lobby_invite.connect(_on_lobby_invite)
|
||||
Steam.lobby_joined.connect(on_lobby_joined)
|
||||
Steam.lobby_match_list.connect(on_lobby_match_list)
|
||||
Steam.lobby_message.connect(on_lobby_message)
|
||||
Steam.persona_state_change.connect(on_persona_change)
|
||||
# Check for command line arguments
|
||||
check_command_line()
|
||||
#Load lobbylist
|
||||
render_global_lobbies()
|
||||
is_initiallized = true
|
||||
|
||||
func _notification(what: int) -> void:
|
||||
if what == NOTIFICATION_WM_CLOSE_REQUEST:
|
||||
# do save stuff here
|
||||
if lobby_id != 0:
|
||||
Steam.leaveLobby(lobby_id)
|
||||
print("[Steam] Left lobby " + str(lobby_id))
|
||||
main.on_Disconnect_pressed()
|
||||
print("Exiting")
|
||||
get_tree().quit()
|
||||
|
||||
func check_command_line() -> void:
|
||||
var args: Array = OS.get_cmdline_args()
|
||||
# There are arguments to process
|
||||
if args.size() <= 0:
|
||||
return
|
||||
# A Steam connection argument exists
|
||||
if args[0] != "+connect_lobby":
|
||||
return
|
||||
# Lobby invite exists so try to connect to it
|
||||
if int(args[1]) <= 0:
|
||||
return
|
||||
print("[Steam] Command line lobby ID: %s" % args[1])
|
||||
join_lobby(int(args[1]))
|
||||
|
||||
func steam_avatar_loaded(user_id: int, avatar_size: int, avatar_buffer: PackedByteArray):
|
||||
var avatar_image: Image = Image.create_from_data(avatar_size, avatar_size, false, Image.FORMAT_RGBA8, avatar_buffer)
|
||||
var avatar_texture: ImageTexture = ImageTexture.create_from_image(avatar_image)
|
||||
if user_id == steam_id:
|
||||
profileSprite.set_texture(avatar_texture)
|
||||
var index = member_index_list.find_key(user_id)
|
||||
if index != null:
|
||||
lobby_members_list.set_item_icon(index,avatar_texture)
|
||||
|
||||
func render_global_lobbies():
|
||||
Steam.addRequestLobbyListDistanceFilter(Steam.LOBBY_DISTANCE_FILTER_WORLDWIDE)
|
||||
Steam.requestLobbyList()
|
||||
|
||||
func on_lobby_match_list(lobbies: Array):
|
||||
list.clear()
|
||||
lobby_index_list = {}
|
||||
await get_tree().create_timer(.05).timeout
|
||||
for lobby in lobbies:
|
||||
var lobby_name = Steam.getLobbyData(lobby,"name")
|
||||
var lobby_mode = Steam.getLobbyData(lobby,"mode")
|
||||
#TODO: Remove when own steam page is aquired
|
||||
if lobby_name == "" or lobby_mode != "Spacebots":
|
||||
continue
|
||||
if Steam.getNumLobbyMembers(lobby) == 0 or lobby == lobby_id:
|
||||
continue
|
||||
var index = list.add_item("%s [%s/%s]" % [lobby_name, Steam.getNumLobbyMembers(lobby), Steam.getLobbyMemberLimit(lobby)] , null, false)
|
||||
list.set_item_tooltip(index, str(lobby))
|
||||
lobby_index_list.set(index,lobby)
|
||||
|
||||
func create_lobby() -> void:
|
||||
if lobby_id != 0: # Make sure a lobby is not already set
|
||||
return
|
||||
|
||||
print("[Steam] Creating Lobby")
|
||||
Steam.createLobby(Steam.LOBBY_TYPE_PUBLIC, lobby_members_max)
|
||||
func on_lobby_created(connect_: int, this_lobby_id: int) -> void:
|
||||
if connect_ != 1:
|
||||
push_error("[Steam] Error creating lobby:" + str(connect_))
|
||||
return
|
||||
# Set the lobby ID
|
||||
lobby_id = this_lobby_id
|
||||
print("[Steam] Created steam lobby: %s" % lobby_id)
|
||||
|
||||
Steam.setLobbyJoinable(lobby_id, true)
|
||||
Steam.setLobbyData(lobby_id, "name", steam_username + "'s lobby")
|
||||
Steam.setLobbyData(lobby_id, "mode", "Spacebots")
|
||||
print("[Steam] Lobbydata set successfully")
|
||||
lobby_members_list.add_item(Steam.getPlayerNickname(steam_id), profileSprite.get_texture(), true)
|
||||
#Allow P2P connections to fallback to being relayed through Steam if needed
|
||||
#var set_relay: bool = Steam.allowP2PPacketRelay(true)
|
||||
#print("Allowing Steam to be relay backup: %s" % set_relay)
|
||||
|
||||
func join_lobby(this_lobby_id: int) -> void:
|
||||
print("[Steam] Attempting to join lobby %s" % this_lobby_id)
|
||||
|
||||
|
||||
# Make the lobby join request to Steam
|
||||
Steam.joinLobby(this_lobby_id)
|
||||
|
||||
func on_lobby_joined(this_lobby_id: int, _permissions: int, _locked: bool, response: int) -> void:
|
||||
# If joining was successful
|
||||
if response != Steam.CHAT_ROOM_ENTER_RESPONSE_SUCCESS:
|
||||
# Get the failure reason
|
||||
var fail_reason: String
|
||||
match response:
|
||||
Steam.CHAT_ROOM_ENTER_RESPONSE_DOESNT_EXIST: fail_reason = "This lobby no longer exists."
|
||||
Steam.CHAT_ROOM_ENTER_RESPONSE_NOT_ALLOWED: fail_reason = "You don't have permission to join this lobby."
|
||||
Steam.CHAT_ROOM_ENTER_RESPONSE_FULL: fail_reason = "The lobby is now full."
|
||||
Steam.CHAT_ROOM_ENTER_RESPONSE_ERROR: fail_reason = "Uh... something unexpected happened!"
|
||||
Steam.CHAT_ROOM_ENTER_RESPONSE_BANNED: fail_reason = "You are banned from this lobby."
|
||||
Steam.CHAT_ROOM_ENTER_RESPONSE_LIMITED: fail_reason = "You cannot join due to having a limited account."
|
||||
Steam.CHAT_ROOM_ENTER_RESPONSE_CLAN_DISABLED: fail_reason = "This lobby is locked or disabled."
|
||||
Steam.CHAT_ROOM_ENTER_RESPONSE_COMMUNITY_BAN: fail_reason = "This lobby is community locked."
|
||||
Steam.CHAT_ROOM_ENTER_RESPONSE_MEMBER_BLOCKED_YOU: fail_reason = "A user in the lobby has blocked you from joining."
|
||||
Steam.CHAT_ROOM_ENTER_RESPONSE_YOU_BLOCKED_MEMBER: fail_reason = "A user you have blocked is in the lobby."
|
||||
print("[Steam] Failed to join lobby : %s" % fail_reason)
|
||||
return
|
||||
lobby_id = this_lobby_id
|
||||
# Clear any previous lobby members lists, if you were in a previous lobby
|
||||
get_lobby_members()
|
||||
# TODO: Add failed to connect dialog
|
||||
|
||||
func on_lobby_join_requested(this_lobby_id: int, friend_id: int) -> void:
|
||||
# Get the lobby owner's name
|
||||
if this_lobby_id == lobby_id:
|
||||
print("[Steam] Lobby join canceled: Already in that lobby")
|
||||
return
|
||||
if lobby_id != 0:
|
||||
print("[Steam] Leaving lobby " + str(lobby_id))
|
||||
leave_lobby()
|
||||
var owner_name: String = Steam.getFriendPersonaName(friend_id)
|
||||
print("[Steam] Joining %s's lobby..." % owner_name)
|
||||
|
||||
# Attempt to join the lobby
|
||||
join_lobby(this_lobby_id)
|
||||
|
||||
func get_lobby_members() -> void:
|
||||
# Clear your previous lobby list
|
||||
lobby_members.clear()
|
||||
lobby_members_list.clear()
|
||||
# Get the number of members from this lobby from Steam
|
||||
var num_of_members: int = Steam.getNumLobbyMembers(lobby_id)
|
||||
|
||||
# Get the data of these players from Steam
|
||||
for this_member in range(0, num_of_members):
|
||||
var member_steam_id: int = Steam.getLobbyMemberByIndex(lobby_id, this_member)
|
||||
var member_steam_name: String = Steam.getFriendPersonaName(member_steam_id)
|
||||
# Add them to the list
|
||||
lobby_members.append({"steam_id":member_steam_id, "steam_name":member_steam_name})
|
||||
Steam.getPlayerAvatar(Steam.AVATAR_SMALL,member_steam_id)
|
||||
if member_steam_id == Steam.getLobbyOwner(lobby_id):
|
||||
member_steam_name += " (Host)"
|
||||
var index: int = lobby_members_list.add_item(member_steam_name, null, true)
|
||||
if member_steam_id != Steam.getLobbyOwner(lobby_id):
|
||||
lobby_members_list.set_item_tooltip_enabled(index, false)
|
||||
else:
|
||||
lobby_members_list.set_item_tooltip(index,str(lobby_id))
|
||||
if Steam.getFriendRelationship(member_steam_id) == Steam.FRIEND_FLAG_IMMEDIATE:
|
||||
list.set_item_custom_fg_color(index, Color(0.9,1,0.9,1))
|
||||
member_index_list.set(index, member_steam_id)
|
||||
|
||||
func on_persona_change(this_steam_id: int, flag: int) -> void:
|
||||
# Make sure you're in a lobby and this user is valid or Steam might spam your console log
|
||||
if lobby_id > 0:
|
||||
var hex : String = "0x%04X" % flag
|
||||
var name_ : String = Steam.getFriendPersonaName(this_steam_id)
|
||||
print("[Steam] %s (%s) had information change, updating member list: %s" % [name_, this_steam_id, hex])
|
||||
# Update the player list
|
||||
get_lobby_members()
|
||||
|
||||
func on_lobby_message(lobby_id_msg: int, user: int, buffer: String, _chat_type: Steam.ChatEntryType):
|
||||
print("[Chat] " + Steam.getFriendPersonaName(user) + ": " + buffer)
|
||||
if(user != Steam.getLobbyOwner(lobby_id)):
|
||||
print("[Steam] Message not by Lobby owner: " + str(lobby_id_msg) + " " + str(Steam.getLobbyOwner(lobby_id)))
|
||||
return
|
||||
if(buffer.begins_with("NorayID:")):
|
||||
buffer = buffer.trim_prefix("NorayID:")
|
||||
print(buffer)
|
||||
$/root/Main.on_Connect(buffer)
|
||||
|
||||
func on_lobby_chat_update(_lobby_id_msg_update: int, _changed_id: int, _changer_id: int, chat_state: Steam.ChatMemberStateChange):
|
||||
print("lobby chat update: " + str(chat_state))
|
||||
if Steam.CHAT_MEMBER_STATE_CHANGE_ENTERED and Steam.getLobbyOwner(lobby_id) == steam_id:
|
||||
var result = Steam.sendLobbyChatMsg(lobby_id, "NorayID:" + str(Noray.oid))
|
||||
print("lobby chat update2: " + str(chat_state))
|
||||
if result == false:
|
||||
print("Chat message couldn't be send")
|
||||
func leave_lobby():
|
||||
Steam.leaveLobby(lobby_id)
|
||||
lobby_id = 0
|
||||
1
script/steamworks.gd.uid
Normal file
1
script/steamworks.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dnygkxv8lwrgw
|
||||
Reference in New Issue
Block a user