Skip to content

Commit

Permalink
Level saving!
Browse files Browse the repository at this point in the history
Reworded some things, and finally implemented level saving! Levels look very strange in FEZ (check the FEZ Community Projects Discord to see what I mean), so there's still a lot of work to do.
  • Loading branch information
edinosma committed Jan 10, 2024
1 parent 207a7a2 commit 36a61d7
Show file tree
Hide file tree
Showing 15 changed files with 66,510 additions and 39 deletions.
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@
3. Load a `.fezlvl.json` file from the File menu! (`.fezlvl.json`s are usually found in the levels directory)

#### Level testing:
1. Use [FEZRepacker](https://github.com/FEZModding/FEZRepacker) to repack the contents of your folder.
2. Drop the new `.pak` file into FEZ. Be sure that FEZ has [HAT](https://github.com/FEZModding/HAT) and [FEZUG](https://github.com/FEZModding/FEZUG) installed!
3. Warp to your level with `warp <level_name>`!
1. Move your level files into their own separate root folder (something like `Beret/levels/`)
1. Use [FEZRepacker](https://github.com/FEZModding/FEZRepacker) to add your levels to your `Other.pak` file. The command should look something like `FEZRepacker.exe --pack "Beret" Other_new.pak Other.pak`
2. Replace the `Other.pak` file in FEZ's `Content` directory with the new `.pak` file. Be sure that FEZ has [HAT](https://github.com/FEZModding/HAT) and [FEZUG](https://github.com/FEZModding/FEZUG) installed!
3. Open the FEZUG console and warp to your level with `warp <level_name>`!
---
### Screenshots
![Screenshot of level "OWL"](https://github.com/edinosma/Beret/blob/master/github/beret_screenshot.png?raw=true)
9 changes: 4 additions & 5 deletions Scenes/Cursor.tscn
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
[ext_resource type="Script" path="res://Scripts/Cursor.gd" id="1_gsw3j"]
[ext_resource type="Material" uid="uid://cwmx5mt2bhij2" path="res://Materials/UI.tres" id="2_0tkj2"]

[sub_resource type="ConvexPolygonShape3D" id="ConvexPolygonShape3D_4lrr7"]
points = PackedVector3Array(0.55, 0.55, 0.549993, 0.55, -0.55, 0.549993, 0.55, 0.55, -0.55, -0.55, 0.55, 0.549993, 0.55, -0.55, -0.55, -0.55, -0.55, 0.549993, -0.55, 0.55, -0.55, -0.55, -0.55, -0.55)
[sub_resource type="SphereShape3D" id="SphereShape3D_87ky0"]
radius = 0.3

[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_i5nyl"]

Expand Down Expand Up @@ -55,16 +55,15 @@ _data = {
}

[node name="Cursor" type="Node3D"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.56, 0.56, 0.56)
script = ExtResource("1_gsw3j")

[node name="Area3D" type="Area3D" parent="."]

[node name="CollisionShape3D" type="CollisionShape3D" parent="Area3D"]
transform = Transform3D(0.9, 0, 0, 0, 0.9, 0, 0, 0, 0.9, 0, 0, 0)
shape = SubResource("ConvexPolygonShape3D_4lrr7")
shape = SubResource("SphereShape3D_87ky0")

[node name="Box" type="MeshInstance3D" parent="."]
transform = Transform3D(1.2, 0, 0, 0, 1.2, 0, 0, 0, 1.2, 0, 0, 0)
layers = 2
cast_shadow = 0
mesh = SubResource("ArrayMesh_351w7")
Expand Down
6 changes: 5 additions & 1 deletion Scenes/MainScene.tscn
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
[gd_scene load_steps=4 format=3 uid="uid://q6hiwea1m8ok"]
[gd_scene load_steps=5 format=3 uid="uid://q6hiwea1m8ok"]

[ext_resource type="PackedScene" uid="uid://djsig0kkd1ved" path="res://Scenes/Cursor.tscn" id="1_qhvts"]
[ext_resource type="PackedScene" uid="uid://cdwpy8hm6qseq" path="res://Scenes/UI.tscn" id="2_7lqbu"]
[ext_resource type="Environment" uid="uid://ctohsq6knqpup" path="res://Materials/DefaultEnv.tres" id="3_tf75n"]
[ext_resource type="PackedScene" uid="uid://dtgqsmedef7w7" path="res://Scenes/Stopper.tscn" id="4_1q8sn"]

[node name="Main" type="Node"]

Expand All @@ -13,5 +14,8 @@
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
environment = ExtResource("3_tf75n")

[node name="Stopper" parent="." instance=ExtResource("4_1q8sn")]
visible = false

[connection signal="cursorPos" from="UI" to="Cursor" method="_on_ui_cursor_pos"]
[connection signal="hasMoved" from="Cursor" to="UI" method="_on_cursor_has_moved"]
50 changes: 50 additions & 0 deletions Scenes/Stopper.tscn
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
[gd_scene load_steps=5 format=3 uid="uid://dtgqsmedef7w7"]

[sub_resource type="PlaneMesh" id="PlaneMesh_svens"]

[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_2attf"]
depth_draw_mode = 1
albedo_color = Color(0.0235294, 0.027451, 0.560784, 1)
disable_receive_shadows = true
proximity_fade_distance = 10.0

[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_gswgw"]
depth_draw_mode = 1
albedo_color = Color(0.121569, 0.984314, 0.156863, 1)
disable_receive_shadows = true

[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_qo6fp"]
depth_draw_mode = 1
albedo_color = Color(1, 0.117647, 0.156863, 1)
disable_receive_shadows = true

[node name="Stopper" type="Node3D"]

[node name="xz" type="MeshInstance3D" parent="."]
transform = Transform3D(25, 0, 0, 0, 25, 0, 0, 0, 25, 0, 0, 0)
layers = 16
visibility_range_end = 50.0
visibility_range_end_margin = 20.0
visibility_range_fade_mode = 1
mesh = SubResource("PlaneMesh_svens")
surface_material_override/0 = SubResource("StandardMaterial3D_2attf")

[node name="yx" type="MeshInstance3D" parent="."]
transform = Transform3D(25, 0, 0, 0, -1.09278e-06, -25, 0, 25, -1.09278e-06, 0, 0, 0)
layers = 16
visibility_range_end = 50.0
visibility_range_end_margin = 20.0
visibility_range_fade_mode = 1
mesh = SubResource("PlaneMesh_svens")
skeleton = NodePath("../xz")
surface_material_override/0 = SubResource("StandardMaterial3D_gswgw")

[node name="yz" type="MeshInstance3D" parent="."]
transform = Transform3D(-1.09278e-06, 25, -1.09278e-06, 0, -1.09278e-06, -25, -25, -1.09278e-06, 4.77671e-14, 0, 0, 0)
layers = 16
visibility_range_end = 50.0
visibility_range_end_margin = 20.0
visibility_range_fade_mode = 1
mesh = SubResource("PlaneMesh_svens")
skeleton = NodePath("../xz")
surface_material_override/0 = SubResource("StandardMaterial3D_qo6fp")
65 changes: 58 additions & 7 deletions Scenes/UI.tscn
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[gd_scene load_steps=18 format=3 uid="uid://cdwpy8hm6qseq"]
[gd_scene load_steps=25 format=3 uid="uid://cdwpy8hm6qseq"]

[ext_resource type="Script" path="res://Scripts/UI/UI.gd" id="1_yufu8"]
[ext_resource type="Theme" uid="uid://5wxvr808qkyw" path="res://default.tres" id="2_i42am"]
Expand All @@ -7,10 +7,11 @@
[ext_resource type="Script" path="res://Scripts/UI/Titlebar/menuView.gd" id="4_i7j77"]
[ext_resource type="Texture2D" uid="uid://cw063pifm8hls" path="res://beret_logo.png" id="5_tfvu3"]
[ext_resource type="PackedScene" uid="uid://baepcmjcgsbk0" path="res://Objects/Compass.glb" id="6_exilt"]
[ext_resource type="Script" path="res://Scripts/Importer/FEZImporter.gd" id="7_8t0yp"]
[ext_resource type="Script" path="res://Scripts/UI/Sidebar/EditorInfo.gd" id="7_jfdyk"]
[ext_resource type="Script" path="res://Scripts/UI/Compass.gd" id="7_lgwbb"]
[ext_resource type="Script" path="res://Scripts/UI/Toolbar/Palette.gd" id="10_yvdlw"]
[ext_resource type="Script" path="res://Scripts/Importer/Importer.gd" id="11_b3xhm"]
[ext_resource type="Script" path="res://Scripts/Exporter/Exporter.gd" id="12_4xdn3"]

[sub_resource type="InputEventKey" id="InputEventKey_kofio"]
device = -1
Expand All @@ -20,6 +21,30 @@ keycode = 70
[sub_resource type="Shortcut" id="Shortcut_aqtus"]
events = [SubResource("InputEventKey_kofio")]

[sub_resource type="InputEventKey" id="InputEventKey_fwuaw"]
device = -1
ctrl_pressed = true
keycode = 79

[sub_resource type="Shortcut" id="Shortcut_8hi2n"]
events = [SubResource("InputEventKey_fwuaw")]

[sub_resource type="InputEventKey" id="InputEventKey_txw7b"]
device = -1
ctrl_pressed = true
keycode = 83

[sub_resource type="Shortcut" id="Shortcut_c4g0v"]
events = [SubResource("InputEventKey_txw7b")]

[sub_resource type="InputEventKey" id="InputEventKey_slhck"]
device = -1
ctrl_pressed = true
keycode = 81

[sub_resource type="Shortcut" id="Shortcut_x4u3j"]
events = [SubResource("InputEventKey_slhck")]

[sub_resource type="InputEventKey" id="InputEventKey_2jet3"]
device = -1
alt_pressed = true
Expand Down Expand Up @@ -55,6 +80,7 @@ layout_mode = 2
shortcut = SubResource("Shortcut_aqtus")
text = "File"
flat = false
switch_on_hover = true
item_count = 5
popup/item_0/text = "Load Level"
popup/item_0/id = 0
Expand All @@ -69,8 +95,11 @@ popup/item_3/separator = true
popup/item_4/text = "Quit"
popup/item_4/id = 4
script = ExtResource("3_mnd5b")
loadShortcut = SubResource("Shortcut_8hi2n")
saveShortcut = SubResource("Shortcut_c4g0v")
quitShortcut = SubResource("Shortcut_x4u3j")

[node name="LoadDialog" type="FileDialog" parent="Titlebar/File"]
[node name="Load" type="FileDialog" parent="Titlebar/File"]
title = "Open a File"
initial_position = 1
size = Vector2i(454, 400)
Expand All @@ -80,16 +109,26 @@ access = 2
filters = PackedStringArray("*.fezlvl.json ; FEZ Levels")
use_native_dialog = true

[node name="Save" type="FileDialog" parent="Titlebar/File"]
title = "Save FEZLVL as"
initial_position = 2
dialog_hide_on_ok = true
access = 2
filters = PackedStringArray("*.fezlvl.json ; FEZ Levels")
use_native_dialog = true

[node name="Edit" type="MenuButton" parent="Titlebar"]
layout_mode = 2
text = "Edit"
flat = false
switch_on_hover = true

[node name="View" type="MenuButton" parent="Titlebar"]
layout_mode = 2
shortcut = SubResource("Shortcut_5p5ho")
text = "View"
flat = false
switch_on_hover = true
item_count = 5
popup/item_0/text = "Palette"
popup/item_0/id = 0
Expand All @@ -114,6 +153,7 @@ layout_mode = 2
shortcut = SubResource("Shortcut_efjk7")
text = "Help"
flat = false
switch_on_hover = true
item_count = 4
popup/item_0/text = "FEZModding Wiki"
popup/item_0/id = 0
Expand Down Expand Up @@ -214,6 +254,7 @@ render_target_update_mode = 0

[node name="Compass" parent="Sidebar/SidebarVertical/CompassView/Compass" instance=ExtResource("6_exilt")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, 0, 0, 0)
visible = false
script = ExtResource("7_lgwbb")

[node name="CompPivot" type="Node3D" parent="Sidebar/SidebarVertical/CompassView/Compass"]
Expand All @@ -237,6 +278,8 @@ layout_mode = 2
layout_mode = 2
size_flags_horizontal = 3
mouse_force_pass_scroll_events = false
theme = ExtResource("2_i42am")
allow_search = false
max_columns = 0
same_column_width = true
icon_scale = 2.0
Expand All @@ -248,12 +291,20 @@ script = ExtResource("10_yvdlw")
process_thread_group = 2
process_thread_group_order = 0
process_thread_messages = 0
script = ExtResource("7_8t0yp")
script = ExtResource("11_b3xhm")

[node name="Exporter" type="Node" parent="."]
process_thread_group = 2
process_thread_group_order = 0
process_thread_messages = 0
script = ExtResource("12_4xdn3")

[connection signal="canceled" from="Titlebar/File/LoadDialog" to="." method="_on_load_dialog_canceled"]
[connection signal="confirmed" from="Titlebar/File/LoadDialog" to="." method="_on_load_dialog_confirmed"]
[connection signal="file_selected" from="Titlebar/File/LoadDialog" to="Loader" method="_on_load_dialog_file_selected"]
[connection signal="canceled" from="Titlebar/File/Load" to="." method="_on_load_dialog_canceled"]
[connection signal="confirmed" from="Titlebar/File/Load" to="." method="_on_load_dialog_confirmed"]
[connection signal="file_selected" from="Titlebar/File/Load" to="Loader" method="_on_load_dialog_file_selected"]
[connection signal="file_selected" from="Titlebar/File/Save" to="Exporter" method="_on_save_file_selected"]
[connection signal="close_requested" from="Titlebar/Help/About" to="Titlebar/Help" method="_on_about_close_requested"]
[connection signal="levelJSON" from="Loader" to="Titlebar/File" method="_on_loader_level_json"]
[connection signal="levelJSON" from="Loader" to="Titlebar/View" method="_on_loader_level_json"]
[connection signal="levelJSON" from="Loader" to="Sidebar/SidebarVertical/EditorLog" method="_on_loader_level_json"]
[connection signal="loadedTS" from="Loader" to="Toolbar/Palette" method="_on_loader_loaded_ts"]
Expand Down
2 changes: 1 addition & 1 deletion Scripts/Cursor.gd
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func _process(_delta):
localCam.look_at(position) # Have the camera always looking at the cursor.
pass

func _input(_event):
func _unhandled_input(_event):
if allowMove: # Movement control. Why does this have to be a bunch of if statements?
var forward = transform.basis.z; var right = -transform.basis.x
var _moveTo = Vector3.ZERO # Prevent cursor from going below (0, 0, 0)
Expand Down
99 changes: 99 additions & 0 deletions Scripts/Exporter/Exporter.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
extends Node

# Exporting is a little more complicated than importing. We have our data, we know what it looks like,
# we just have to get it out in a way FEZ likes. To help with this, I made a "template" file that we can
# overwrite with our data.

@onready var _loader = $"../Loader"

var lvlSize = [0, 0, 0]

# Standard definitions. This will get ugly!
var _aoActor = { "Inactive": false, "ContainedTrile": "None", "AttachedGroup": null, "SpinView": "None", "SpinEvery": 0, "SpinOffset": 0, "OffCenter": false, "RotationCenter": [0, 0, 0], "VibrationPattern": [], "CodePattern": [], "Segment": { "Destination": [0, 0, 0], "Duration": 1, "WaitTimeOnStart": 0, "WaitTimeOnFinish": 0, "Acceleration": 0, "Deceleration": 0, "JitterFactor": 0, "Orientation": [0, 0, 0, 1], "CustomData": null }, "NextNode": null, "DestinationLevel": "", "TreasureMapName": "", "InvisibleSides": [], "TimeswitchWindBackSpeed": 0}

func _on_save_file_selected(path: String):
var adjPath = path.get_slice(".", 0) # Get just the filename, in case the user puts in file extension.
var filename = adjPath.get_file()
var cleanPath = adjPath.get_base_dir()

_saveFEZLVL(cleanPath, filename)
pass # Replace with function body.

func _saveFEZLVL(path, filename):
var readTemp = JSON.new()
var err = readTemp.parse(FileAccess.get_file_as_string("res://Scripts/Exporter/template.fezlvl.json"))
if err == OK:
var template = readTemp.data
# Get all of Loader's children.
for n in _loader.get_child_count():
var obj = _loader.get_child(n)
var type = obj.get_meta("Type")

match type:
"Trile":
var pos = [obj.position.x, obj.position.y, obj.position.z]
var emp = [round(pos[0]), round(pos[1]), round(pos[2])]
var phi = 0
var actset = null

var trileDict = { "Emplacement": emp,
"Position": pos,
"Phi": phi,
"Id": int(obj.get_meta("Id")),
"ActorSettings": actset}

template["Triles"].append(trileDict)
pass

"AO":
var aoName = obj.get_meta("Name")
var pos = [obj.position.x, obj.position.y, obj.position.z]
var rot = [obj.quaternion.x, obj.quaternion.y, obj.quaternion.z, obj.quaternion.w]
var aoScale = [obj.scale.x, obj.scale.y, obj.scale.z]
var actset = _aoActor

var aoDict = { "Name": aoName.to_upper(),
"Position": pos,
"Rotation": rot,
"Scale": aoScale,
"ActorSettings": actset}
var arrIdx = template["ArtObjects"].size() + 1
var metaDict = { str(arrIdx) : aoDict}

template["ArtObjects"].merge(metaDict)
pass

"StartingPoint":
var id = obj.get_meta("Id")
var face = obj.get_meta("Face")
var spDict = { "Id": id, "Face": face}

template["StartingPosition"] = spDict
pass
pass
template["Name"] = filename.to_upper()
template["TrileSetName"] = _loader.trileset[3].to_upper()

# Find the level's size automatically by finding the most out-there object.
var maxX = _findLargest(template["Triles"], 0)
var maxY = _findLargest(template["Triles"], 1)
var maxZ = _findLargest(template["Triles"], 2)
template["Size"] = [maxX, maxY, maxZ]

print("Done writing file. Phew!")

var writeLVL := JSON.stringify(template, " ", false, false)

var file = FileAccess.open(path + "/" + filename + ".fezlvl.json", FileAccess.WRITE)
file.store_string(writeLVL)
file.close()
pass
pass

func _findLargest(triles, idx: int):
var comparer: int = 1
for trile in triles:
if trile["Position"][idx] > comparer:
comparer = trile["Position"][idx]
pass
return comparer
Loading

0 comments on commit 36a61d7

Please sign in to comment.