start implementing stores
This commit is contained in:
parent
c5cb73867f
commit
b4cb70a798
|
@ -29,9 +29,3 @@ func set_state(state):
|
|||
else:
|
||||
button.icon = false
|
||||
button.label = name
|
||||
|
||||
func _save():
|
||||
return {
|
||||
"transform": transform,
|
||||
"entity_id": entity_id
|
||||
}
|
||||
|
|
|
@ -57,9 +57,3 @@ func load_image(url: String):
|
|||
view.texture = texture
|
||||
view.pixel_size = pixel_size
|
||||
mesh.visible = false
|
||||
|
||||
func _save():
|
||||
return {
|
||||
"transform": transform,
|
||||
"entity_id": entity_id
|
||||
}
|
||||
|
|
|
@ -56,9 +56,3 @@ func _on_click(event):
|
|||
|
||||
HomeApi.set_state(entity_id, "on" if !state else "off", attributes)
|
||||
set_state(!state, brightness)
|
||||
|
||||
func _save():
|
||||
return {
|
||||
"transform": transform,
|
||||
"entity_id": entity_id
|
||||
}
|
|
@ -86,9 +86,3 @@ func load_image(url: String):
|
|||
var texture = ImageTexture.create_from_image(image)
|
||||
logo.texture = texture
|
||||
logo.pixel_size = pixel_size
|
||||
|
||||
func _save():
|
||||
return {
|
||||
"transform": transform,
|
||||
"entity_id": entity_id
|
||||
}
|
|
@ -22,9 +22,3 @@ func set_text(stateInfo):
|
|||
text += " " + stateInfo["attributes"]["unit_of_measurement"]
|
||||
|
||||
label.text = text
|
||||
|
||||
func _save():
|
||||
return {
|
||||
"transform": transform,
|
||||
"entity_id": entity_id
|
||||
}
|
|
@ -31,9 +31,3 @@ func _on_click(event):
|
|||
|
||||
func _on_request_completed():
|
||||
pass
|
||||
|
||||
func _save():
|
||||
return {
|
||||
"transform": transform,
|
||||
"entity_id": entity_id
|
||||
}
|
|
@ -44,3 +44,12 @@ func get_new_transform(old_transform: Transform3D):
|
|||
marker.scale = Vector3(1, 1, 1)
|
||||
return marker.global_transform
|
||||
|
||||
func update_align_reference():
|
||||
corner1.global_position = Store.house.align_position1
|
||||
corner2.global_position = Store.house.align_position2
|
||||
|
||||
edge.align_to_corners(corner1.global_position, corner2.global_position)
|
||||
|
||||
func update_store():
|
||||
Store.house.align_position1 = corner1.global_position
|
||||
Store.house.align_position2 = corner2.global_position
|
|
@ -16,11 +16,29 @@ var mini_view: bool = false:
|
|||
|
||||
var target_size: float = 1.0
|
||||
|
||||
func _ready():
|
||||
Store.house.on_loaded.connect(func():
|
||||
update_house()
|
||||
)
|
||||
|
||||
func _physics_process(delta):
|
||||
levels.scale.x = lerp(levels.scale.x, target_size, 10.0 * delta)
|
||||
levels.scale.y = lerp(levels.scale.y, target_size, 10.0 * delta)
|
||||
levels.scale.z = lerp(levels.scale.z, target_size, 10.0 * delta)
|
||||
|
||||
func update_house():
|
||||
for room in get_rooms(0):
|
||||
room.queue_free()
|
||||
|
||||
align_reference.update_align_reference()
|
||||
|
||||
for room in Store.house.rooms:
|
||||
create_room(room.name, 0)
|
||||
# TODO: Make room load itself!
|
||||
|
||||
for entity in Store.house.entities:
|
||||
var entity_instance = create_entity(entity.id, entity.position)
|
||||
entity_instance.global_rotation = entity.rotation
|
||||
|
||||
func create_room(room_name: String, level: int) -> RoomType:
|
||||
if editing_room != null:
|
||||
|
@ -34,6 +52,12 @@ func create_room(room_name: String, level: int) -> RoomType:
|
|||
|
||||
get_level(level).add_child(room)
|
||||
|
||||
Store.house.rooms.append({
|
||||
"name": room_name,
|
||||
"height": 2.0,
|
||||
"corners": [],
|
||||
})
|
||||
|
||||
return room
|
||||
|
||||
func edit_room(room_name):
|
||||
|
@ -75,17 +99,15 @@ func is_editiong(room_name):
|
|||
return editing_room != null && editing_room.name == room_name
|
||||
|
||||
func find_room(room_name):
|
||||
for level in levels.get_children():
|
||||
for room in level.get_children():
|
||||
if room.name == room_name:
|
||||
return room
|
||||
for room in get_rooms(0):
|
||||
if room.name == room_name:
|
||||
return room
|
||||
return null
|
||||
|
||||
func find_room_at(entity_position: Vector3):
|
||||
for level in levels.get_children():
|
||||
for room in level.get_children():
|
||||
if room.has_point(entity_position):
|
||||
return room
|
||||
for room in get_rooms(0):
|
||||
if room.has_point(entity_position):
|
||||
return room
|
||||
return null
|
||||
|
||||
func get_level(level: int):
|
||||
|
@ -127,9 +149,11 @@ func create_entity(entity_id: String, entity_position: Vector3):
|
|||
if entity == null:
|
||||
return
|
||||
|
||||
room.add_child(entity)
|
||||
room.get_node("Entities").add_child(entity)
|
||||
entity.global_position = entity_position
|
||||
|
||||
return entity
|
||||
|
||||
func update_mini_view():
|
||||
collision_shape.disabled = !mini_view
|
||||
|
||||
|
@ -166,3 +190,21 @@ func save_reference():
|
|||
|
||||
align_reference.disabled = true
|
||||
align_reference.update_initial_positions()
|
||||
|
||||
align_reference.update_store()
|
||||
Store.house.save_local()
|
||||
|
||||
func save_all_entities():
|
||||
Store.house.entities.clear()
|
||||
|
||||
for room in get_rooms(0):
|
||||
for entity in room.get_node("Entities").get_children():
|
||||
var entity_data = {
|
||||
"id": entity.entity_id,
|
||||
"position": entity.global_position,
|
||||
"rotation": entity.global_rotation,
|
||||
"room": room.name
|
||||
}
|
||||
|
||||
Store.house.entities.append(entity_data)
|
||||
|
|
@ -51,3 +51,16 @@ func get_aabb():
|
|||
max_pos.y = room_ceiling.position.y
|
||||
|
||||
return AABB(to_global(min_pos), to_global(max_pos) - to_global(min_pos))
|
||||
|
||||
func update_store():
|
||||
var store_room = Store.house.get_room(name)
|
||||
|
||||
var corners = []
|
||||
|
||||
for corner in wall_corners.get_children():
|
||||
corners.append(Vector2(corner.position.x, corner.position.z))
|
||||
|
||||
store_room.corners = corners
|
||||
store_room.height = room_ceiling.position.y
|
||||
|
||||
Store.house.save_local()
|
||||
|
|
|
@ -65,3 +65,5 @@ script = ExtResource("7_ap14h")
|
|||
|
||||
[node name="Mini" type="Node" parent="StateMachine"]
|
||||
script = ExtResource("6_g4qca")
|
||||
|
||||
[node name="Entities" type="Node3D" parent="."]
|
||||
|
|
|
@ -32,6 +32,8 @@ func _on_enter():
|
|||
room.room_floor.get_node("Clickable").on_click.connect(_on_click_floor)
|
||||
|
||||
func _on_leave():
|
||||
room.update_store()
|
||||
|
||||
room.wall_corners.visible = false
|
||||
room.wall_edges.visible = false
|
||||
|
||||
|
@ -68,7 +70,7 @@ func add_floor_corner(position: Vector3):
|
|||
floor_corner.position = position
|
||||
|
||||
height_edge = wall_edge_scene.instantiate()
|
||||
height_edge.align_to_corners(position, position + Vector3.UP * room.room_ceiling.global_position.y)
|
||||
height_edge.align_to_corners(position, position + Vector3.UP * room.room_ceiling.position.y)
|
||||
|
||||
floor_corner.get_node("Clickable").on_grab_down.connect(func(event):
|
||||
if !is_active() || moving != null:
|
||||
|
|
|
@ -34,32 +34,29 @@ func _ready():
|
|||
credits_instance.global_position = + label.to_global(label.position + Vector3(0.1, 0, -0.15))
|
||||
)
|
||||
|
||||
var config = ConfigData.load_config()
|
||||
|
||||
if config.has("url"):
|
||||
input_url.text = config["url"]
|
||||
if config.has("token"):
|
||||
input_token.text = config["token"]
|
||||
input_url.text = Store.settings.url
|
||||
input_token.text = Store.settings.token
|
||||
|
||||
button_connect.on_button_down.connect(func():
|
||||
var url = input_url.text + "/api/websocket"
|
||||
var url = input_url.text
|
||||
var token = input_token.text
|
||||
|
||||
HomeApi.start_adapter("hass_ws", url, token)
|
||||
|
||||
ConfigData.save_config({
|
||||
"api_type": "hass_ws",
|
||||
"url": input_url.text,
|
||||
"token": input_token.text
|
||||
})
|
||||
Store.settings.url = url
|
||||
Store.settings.token = token
|
||||
|
||||
Store.settings.save_local()
|
||||
)
|
||||
|
||||
save.on_button_down.connect(func():
|
||||
SaveSystem.save()
|
||||
House.body.save_all_entities()
|
||||
Store.house.save_local()
|
||||
)
|
||||
|
||||
clear_save.on_button_down.connect(func():
|
||||
SaveSystem.clear()
|
||||
Store.house.clear()
|
||||
House.body.update_house()
|
||||
)
|
||||
|
||||
HomeApi.on_connect.connect(func():
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
extends Node
|
||||
|
||||
const VariantSerializer = preload("res://lib/utils/variant_serializer.gd")
|
||||
|
||||
var file_url: String = "user://config.cfg"
|
||||
|
||||
func save_config(data: Dictionary):
|
||||
var file := FileAccess.open(file_url, FileAccess.WRITE)
|
||||
|
||||
if file == null:
|
||||
return
|
||||
|
||||
var json_data := JSON.stringify(VariantSerializer.stringify_value(data))
|
||||
file.store_string(json_data)
|
||||
|
||||
func load_config():
|
||||
var file := FileAccess.open(file_url, FileAccess.READ)
|
||||
|
||||
if file == null:
|
||||
return {}
|
||||
|
||||
var json_data := file.get_as_text()
|
||||
var data = VariantSerializer.parse_value(JSON.parse_string(json_data))
|
||||
|
||||
return data
|
|
@ -24,14 +24,10 @@ var api: Node
|
|||
func _ready():
|
||||
print("HomeApi ready")
|
||||
|
||||
var config = ConfigData.load_config()
|
||||
var success = Store.settings.load_local()
|
||||
|
||||
if config.has("api_type") && config.has("url") && config.has("token"):
|
||||
var type = config["api_type"]
|
||||
var url = config["url"] + "/api/websocket"
|
||||
var token = config["token"]
|
||||
|
||||
start_adapter(type, url, token)
|
||||
if success:
|
||||
start_adapter(Store.settings.type, Store.settings.url, Store.settings.token)
|
||||
|
||||
|
||||
func start_adapter(type: String, url: String, token: String):
|
||||
|
@ -47,7 +43,7 @@ func start_adapter(type: String, url: String, token: String):
|
|||
add_child(api)
|
||||
|
||||
api.on_connect.connect(func():
|
||||
SaveSystem.load()
|
||||
Store.house.load_local()
|
||||
on_connect.emit()
|
||||
)
|
||||
|
||||
|
@ -96,5 +92,5 @@ func watch_state(entity: String, callback: Callable):
|
|||
|
||||
func _notification(what):
|
||||
if what == NOTIFICATION_WM_CLOSE_REQUEST || what == NOTIFICATION_WM_GO_BACK_REQUEST:
|
||||
# SaveSystem.save()
|
||||
# Store.house.save_local()
|
||||
pass
|
9
lib/globals/main_store.gd
Normal file
9
lib/globals/main_store.gd
Normal file
|
@ -0,0 +1,9 @@
|
|||
extends Node
|
||||
|
||||
const SettingsStore = preload("res://lib/stores/settings.gd")
|
||||
const HouseStore = preload("res://lib/stores/house.gd")
|
||||
const DevicesStore = preload("res://lib/stores/devices.gd")
|
||||
|
||||
var settings = SettingsStore.new()
|
||||
var house = HouseStore.new()
|
||||
var devices = DevicesStore.new()
|
|
@ -1,140 +0,0 @@
|
|||
extends Node
|
||||
|
||||
const VariantSerializer = preload("res://lib/utils/variant_serializer.gd")
|
||||
|
||||
signal loaded()
|
||||
signal unloaded()
|
||||
|
||||
var is_loaded := false
|
||||
var export_config = ConfigFile.new()
|
||||
var export_config_path = "res://export_presets.cfg"
|
||||
|
||||
func clear():
|
||||
await _clear_save_tree(get_tree().root.get_node("Main"))
|
||||
unloaded.emit()
|
||||
is_loaded = false
|
||||
|
||||
func save():
|
||||
if HomeApi.has_connected() == false:
|
||||
return
|
||||
|
||||
var filename = HomeApi.api.url.split("//")[1].replace("/api/websocket", "").replace(".", "_").replace(":", "_")
|
||||
|
||||
var save_file = FileAccess.open("user://%s.save" % filename, FileAccess.WRITE)
|
||||
|
||||
if save_file == null:
|
||||
return
|
||||
|
||||
var save_tree = _generate_save_tree(get_tree().root.get_node("Main"))
|
||||
|
||||
var json_text = JSON.stringify({
|
||||
"version": get_version(),
|
||||
"tree": save_tree
|
||||
})
|
||||
save_file.store_line(json_text)
|
||||
|
||||
func load():
|
||||
await clear()
|
||||
|
||||
if HomeApi.has_connected() == false:
|
||||
return
|
||||
|
||||
var filename = HomeApi.api.url.split("//")[1].replace("/api/websocket", "").replace(".", "_").replace(":", "_")
|
||||
|
||||
var save_file = FileAccess.open("user://%s.save" % filename, FileAccess.READ)
|
||||
|
||||
if save_file == null:
|
||||
return
|
||||
|
||||
var json_text = save_file.get_line()
|
||||
var save_data = JSON.parse_string(json_text)
|
||||
|
||||
if save_data == null:
|
||||
return
|
||||
|
||||
if save_data.has("version") == false:
|
||||
save()
|
||||
return
|
||||
|
||||
var save_tree = save_data["tree"]
|
||||
|
||||
if save_tree == null:
|
||||
return
|
||||
|
||||
if save_tree is Array:
|
||||
for tree in save_tree:
|
||||
_build_save_tree(tree)
|
||||
else:
|
||||
_build_save_tree(save_tree)
|
||||
|
||||
loaded.emit()
|
||||
is_loaded = true
|
||||
|
||||
func get_version():
|
||||
var config_error = export_config.load(export_config_path)
|
||||
|
||||
if config_error != OK:
|
||||
return null
|
||||
|
||||
var version = export_config.get_value("preset.1.options", "version/name")
|
||||
|
||||
if version == null:
|
||||
return null
|
||||
|
||||
return version
|
||||
|
||||
func _clear_save_tree(node: Node):
|
||||
for child in node.get_children():
|
||||
await _clear_save_tree(child)
|
||||
|
||||
if node.has_method("_save"):
|
||||
node.queue_free()
|
||||
await node.tree_exited
|
||||
|
||||
func _generate_save_tree(node: Node):
|
||||
var children = []
|
||||
|
||||
if node.has_method("_save") == false:
|
||||
for child in node.get_children():
|
||||
var data = _generate_save_tree(child)
|
||||
|
||||
if data is Array:
|
||||
for child_data in data:
|
||||
children.append(child_data)
|
||||
else:
|
||||
children.append(data)
|
||||
return children
|
||||
|
||||
|
||||
var save_tree = {
|
||||
"data": VariantSerializer.stringify_value(node.call("_save")),
|
||||
"parent": node.get_parent().get_path(),
|
||||
"filename": node.get_scene_file_path()
|
||||
}
|
||||
|
||||
for child in node.get_children():
|
||||
var child_data = _generate_save_tree(child)
|
||||
|
||||
if child_data is Array:
|
||||
for data in child_data:
|
||||
children.append(data)
|
||||
else:
|
||||
children.append(child_data)
|
||||
|
||||
save_tree["children"] = children
|
||||
|
||||
return save_tree
|
||||
|
||||
func _build_save_tree(tree: Dictionary):
|
||||
var new_object = load(tree["filename"]).instantiate()
|
||||
|
||||
if new_object.has_method("_load"):
|
||||
new_object.call("_load", VariantSerializer.parse_value(tree["data"]))
|
||||
else:
|
||||
for key in tree["data"].keys():
|
||||
new_object.set(key, VariantSerializer.parse_value(tree["data"][key]))
|
||||
|
||||
get_node(tree["parent"]).add_child(new_object)
|
||||
|
||||
for child in tree["children"]:
|
||||
_build_save_tree(child)
|
|
@ -34,13 +34,13 @@ func connect_ws():
|
|||
if url == "" || token == "":
|
||||
return
|
||||
|
||||
print("Connecting to %s" % self.url)
|
||||
socket.connect_to_url(self.url)
|
||||
print("Connecting to %s" % url + "/api/websocket")
|
||||
socket.connect_to_url(url + "/api/websocket")
|
||||
set_process(true)
|
||||
|
||||
# https://github.com/godotengine/godot/issues/84423
|
||||
# Otherwise the WebSocketPeer will crash when receiving large packets
|
||||
socket.set_inbound_buffer_size(pow(2, 22)) # ~4MB buffer
|
||||
socket.set_inbound_buffer_size(pow(2, 23)) # ~8MB buffer
|
||||
|
||||
func _process(delta):
|
||||
socket.poll()
|
||||
|
|
5
lib/stores/devices.gd
Normal file
5
lib/stores/devices.gd
Normal file
|
@ -0,0 +1,5 @@
|
|||
extends StoreClass
|
||||
const StoreClass = preload("./store.gd")
|
||||
|
||||
func clear():
|
||||
pass
|
30
lib/stores/house.gd
Normal file
30
lib/stores/house.gd
Normal file
|
@ -0,0 +1,30 @@
|
|||
extends StoreClass
|
||||
|
||||
const StoreClass = preload("./store.gd")
|
||||
|
||||
# Type Room
|
||||
# name: String
|
||||
# corners: Vec2[]
|
||||
# height: float
|
||||
var rooms = []
|
||||
# Type Entity
|
||||
# id: String
|
||||
# position: Vec3
|
||||
# rotation: Vec3
|
||||
# room: String
|
||||
var entities = []
|
||||
var align_position1: Vector3
|
||||
var align_position2: Vector3
|
||||
|
||||
|
||||
func _init():
|
||||
_save_path = "user://house.json"
|
||||
|
||||
func clear():
|
||||
pass
|
||||
|
||||
func get_room(name):
|
||||
for room in rooms:
|
||||
if room.name == name:
|
||||
return room
|
||||
return null
|
16
lib/stores/settings.gd
Normal file
16
lib/stores/settings.gd
Normal file
|
@ -0,0 +1,16 @@
|
|||
extends StoreClass
|
||||
|
||||
const StoreClass = preload("./store.gd")
|
||||
|
||||
|
||||
var type: String = "HASS_WS"
|
||||
var url: String = ""
|
||||
var token: String = ""
|
||||
|
||||
func _init():
|
||||
_save_path = "user://settings.json"
|
||||
|
||||
func clear():
|
||||
type = "HASS_WS"
|
||||
url = ""
|
||||
token = ""
|
77
lib/stores/store.gd
Normal file
77
lib/stores/store.gd
Normal file
|
@ -0,0 +1,77 @@
|
|||
extends RefCounted
|
||||
|
||||
const VariantSerializer = preload("res://lib/utils/variant_serializer.gd")
|
||||
|
||||
signal on_loaded
|
||||
signal on_saved
|
||||
|
||||
var _loaded = false
|
||||
var _save_path = null
|
||||
|
||||
func is_loaded():
|
||||
return _loaded
|
||||
|
||||
func clear():
|
||||
pass
|
||||
|
||||
func create_dict():
|
||||
var data: Dictionary = {}
|
||||
|
||||
for prop_info in get_property_list():
|
||||
if prop_info.name.begins_with("_") || prop_info.hint_string != "":
|
||||
continue
|
||||
|
||||
var prop = get(prop_info.name)
|
||||
|
||||
if prop is Store:
|
||||
data[prop_info.name] = prop.create_dict()
|
||||
else:
|
||||
data[prop_info.name] = VariantSerializer.stringify_value(prop)
|
||||
|
||||
return data
|
||||
|
||||
func use_dict(dict: Dictionary):
|
||||
for prop_info in get_property_list():
|
||||
if prop_info.name.begins_with("_"):
|
||||
continue
|
||||
|
||||
var prop = get(prop_info.name)
|
||||
var prop_value = dict[prop_info.name]
|
||||
|
||||
if prop is Store:
|
||||
prop.use_dict(prop_value)
|
||||
else:
|
||||
set(prop_info.name, prop_value)
|
||||
|
||||
func save_local(path = _save_path):
|
||||
if path == null:
|
||||
return false
|
||||
|
||||
var data = create_dict()
|
||||
|
||||
var save_file = FileAccess.open(path, FileAccess.WRITE)
|
||||
|
||||
if save_file == null:
|
||||
return false
|
||||
|
||||
var json_text = JSON.stringify(data)
|
||||
save_file.store_line(json_text)
|
||||
|
||||
_loaded = true
|
||||
on_loaded.emit()
|
||||
|
||||
return true
|
||||
|
||||
func load_local(path = _save_path):
|
||||
if path == null:
|
||||
return false
|
||||
|
||||
var save_file = FileAccess.open(path, FileAccess.READ)
|
||||
|
||||
if save_file == null:
|
||||
return false
|
||||
|
||||
var json_text = save_file.get_line()
|
||||
var save_data = VariantSerializer.parse_value(JSON.parse_string(json_text))
|
||||
|
||||
use_dict(save_data)
|
|
@ -30,3 +30,9 @@ func change_to(new_state: String) -> void:
|
|||
add_child(current_state)
|
||||
current_state._on_enter()
|
||||
changed.emit(new_state, old_state)
|
||||
|
||||
func get_state(state_name: String) -> Node:
|
||||
if states.has(state_name) == false:
|
||||
return null
|
||||
|
||||
return states[state_name]
|
|
@ -11,7 +11,7 @@ static func stringify_value(value):
|
|||
return value.map(func(item):
|
||||
return stringify_value(item)
|
||||
)
|
||||
TYPE_BOOL, TYPE_INT, TYPE_FLOAT, TYPE_STRING:
|
||||
TYPE_BOOL, TYPE_INT, TYPE_FLOAT, TYPE_STRING, TYPE_NIL:
|
||||
return value
|
||||
TYPE_VECTOR2:
|
||||
return {
|
||||
|
|
|
@ -18,12 +18,11 @@ config/icon="res://assets/logo.png"
|
|||
[autoload]
|
||||
|
||||
XRToolsUserSettings="*res://addons/godot-xr-tools/user_settings/user_settings.gd"
|
||||
ConfigData="*res://lib/globals/config_data.gd"
|
||||
Request="*res://lib/globals/request.gd"
|
||||
HomeApi="*res://lib/globals/home_api.gd"
|
||||
AudioPlayer="*res://lib/globals/audio_player.gd"
|
||||
EventSystem="*res://lib/globals/event_system.gd"
|
||||
SaveSystem="*res://lib/globals/save_system.gd"
|
||||
Store="*res://lib/globals/main_store.gd"
|
||||
House="*res://lib/globals/house_body.gd"
|
||||
|
||||
[editor_plugins]
|
||||
|
|
Loading…
Reference in New Issue
Block a user