1use r2g_mlua::prelude::*;
2
3use crate::core::FastFlags;
4use crate::core::{get_state, inheritance_cast_to, FastFlag, InheritanceBase, InheritanceTable, InheritanceTableBuilder, Irc,
5 ParallelDispatch::Synchronized, RwLock, RwLockReadGuard, RwLockWriteGuard};
6use crate::core::lua_macros::{lua_getter, lua_invalid_argument};
7use crate::userdata::{ManagedRBXScriptSignal, RBXScriptSignal};
8
9use super::{IInstanceComponent, DynInstance, IInstance, IObject, IServiceProvider, InstanceComponent, ManagedInstance, ServiceProviderComponent, WeakManagedInstance};
10
11#[derive(Debug)]
12pub struct DataModelComponent {
13 bind_close: ManagedRBXScriptSignal,
14 workspace: (), pub graphics_quality_change_request: ManagedRBXScriptSignal,
17 pub loaded: ManagedRBXScriptSignal,
18 is_loaded: bool
19
20}
21
22#[derive(Debug)]
23pub struct DataModel {
24 instance: RwLock<InstanceComponent>,
25 service_provider: RwLock<ServiceProviderComponent>,
26 data_model: RwLock<DataModelComponent>
27}
28
29pub trait IDataModel {
30 fn get_data_model_component(&self) -> RwLockReadGuard<'_,DataModelComponent>;
31 fn get_data_model_component_mut(&self) -> RwLockWriteGuard<'_,DataModelComponent>;
32}
33
34impl InheritanceBase for DataModel {
35 fn inheritance_table(&self) -> InheritanceTable {
36 InheritanceTableBuilder::new()
37 .insert_type::<DataModel, dyn IObject>(|x| x, |x| x)
38 .insert_type::<DataModel, DynInstance>(|x| x, |x| x)
39 .insert_type::<DataModel, dyn IServiceProvider>(|x| x, |x| x)
40 .insert_type::<DataModel, dyn IDataModel>(|x| x, |x| x)
41 .output()
42 }
43}
44
45impl IObject for DataModel {
46 fn lua_get(&self, lua: &Lua, name: String) -> LuaResult<LuaValue> {
47 self.data_model.read().unwrap().lua_get(self, lua, &name)
48 .or_else(|| self.service_provider.read().unwrap().lua_get(self, lua, &name))
49 .unwrap_or_else(|| self.instance.read().unwrap().lua_get(lua, &name))
50 }
51
52 fn get_class_name(&self) -> &'static str { "DataModel" }
53
54 fn get_property_changed_signal(&self, property: String) -> ManagedRBXScriptSignal {
55 self.get_instance_component().get_property_changed_signal(property).unwrap()
56 }
57
58 fn is_a(&self, class_name: &String) -> bool {
59 match class_name.as_str() {
60 "DataModel" => true,
61 "ServiceProvider" => true,
62 "Instance" => true,
63 "Object" => true,
64 _ => false
65 }
66 }
67
68 fn get_changed_signal(&self) -> ManagedRBXScriptSignal {
69 self.get_instance_component().changed.clone()
70 }
71}
72
73impl IInstance for DataModel {
74 fn get_instance_component(&self) -> RwLockReadGuard<InstanceComponent> {
75 self.instance.read().unwrap()
76 }
77
78 fn get_instance_component_mut(&self) -> RwLockWriteGuard<InstanceComponent> {
79 self.instance.write().unwrap()
80 }
81
82 fn lua_set(&self, lua: &Lua, name: String, val: LuaValue) -> LuaResult<()> {
83 self.data_model.write().unwrap().lua_set(self, lua, &name, &val)
84 .or_else(|| self.service_provider.write().unwrap().lua_set(self, lua, &name, &val))
85 .unwrap_or_else(|| self.instance.write().unwrap().lua_set(lua, &name, val))
86 }
87
88 fn clone_instance(&self, _: &Lua) -> LuaResult<ManagedInstance> {
89 Err(LuaError::RuntimeError("DataModel cannot be cloned".into()))
90 }
91}
92
93impl IServiceProvider for DataModel {
94 fn get_service_provider_component(&self) -> RwLockReadGuard<ServiceProviderComponent> {
95 self.service_provider.read().unwrap()
96 }
97
98 fn get_service_provider_component_mut(&self) -> RwLockWriteGuard<ServiceProviderComponent> {
99 self.service_provider.write().unwrap()
100 }
101
102 fn get_service(&self, service_name: String) -> LuaResult<ManagedInstance> {
103 self.find_service(service_name)
104 .and_then(|x|
105 x.ok_or_else(|| LuaError::RuntimeError("Service not found".into()))
106 )
107 }
108
109 fn find_service(&self, service_name: String) -> LuaResult<Option<ManagedInstance>> {
110 DynInstance::find_first_child_of_class(self, service_name)
111 }
112}
113
114impl DataModel {
115 pub fn new(flags: &FastFlags) -> ManagedInstance {
116 let game: Irc<DynInstance> = Irc::new_cyclic(|x|
117 DataModel {
118 instance: RwLock::new_with_flag_auto(InstanceComponent::new(x.cast_to_instance(), "DataModel")),
119 service_provider: RwLock::new_with_flag_auto(ServiceProviderComponent::new(x.cast_to_instance(), "DataModel")),
120 data_model: RwLock::new_with_flag_auto(DataModelComponent::new(x.cast_to_instance(), "DataModel"))
121 }).cast_from_sized().unwrap();
122 game.set_name(flags.get_string(FastFlag::GameName)).unwrap();
123 game.lock_parent();
124 game
125 }
126}
127
128impl IInstanceComponent for DataModelComponent {
129 fn lua_get(self: &mut RwLockReadGuard<'_, Self>, _ptr: &DynInstance, lua: &Lua, key: &String) -> Option<LuaResult<LuaValue>> {
130 match key.as_str() {
131 "CreatorId" => Some(lua_getter!(lua, get_state(lua).flags().get_int(FastFlag::CreatorId))),
132 "CreatorType" => todo!(),
133 "GameId" => Some(lua_getter!(lua, get_state(lua).flags().get_int(FastFlag::GameId))),
134 "JobId" => Some(lua_getter!(lua, get_state(lua).flags().get_string(FastFlag::JobId))),
135 "PlaceId" => Some(lua_getter!(lua, get_state(lua).flags().get_int(FastFlag::PlaceId))),
136 "PlaceVersion" => Some(lua_getter!(lua, get_state(lua).flags().get_int(FastFlag::PlaceVersion))),
137 "PrivateServerId" => Some(lua_getter!(lua, get_state(lua).flags().get_string(FastFlag::PrivateServerId))),
138 "PrivateServerOwnerId" => Some(lua_getter!(lua, get_state(lua).flags().get_int(FastFlag::PrivateServerOwnerId))),
139 "Workspace" => todo!(),
140 "BindToClose" => lua_getter!(function_opt, lua, |lua, (this, func): (ManagedInstance, LuaFunction)| {
141 inheritance_cast_to!(&*this, dyn IDataModel)
142 .map_err(|_|
143 lua_invalid_argument!("DataModel::BindToClose",1,self cast Instance to DataModel)
144 )
145 .and_then(|x|
146 x.bind_to_close(lua, func)
147 )
148 }),
149 "IsLoaded" => Some(Ok(LuaValue::Boolean(true))),
150 "GraphicsQualityChangeRequest" => Some(lua_getter!(clone, lua, self.graphics_quality_change_request)),
151 "Loaded" => Some(lua_getter!(clone, lua, self.loaded)),
152 _ => None
153 }
154 }
155
156 fn lua_set(self: &mut RwLockWriteGuard<'_, Self>, _ptr: &DynInstance, _lua: &Lua, key: &String, _value: &LuaValue) -> Option<LuaResult<()>> {
157 match key.as_str() {
158 "CreatorId" |
159 "CreatorType" |
160 "GameId" |
161 "JobId" |
162 "PlaceId" |
163 "PlaceVersion" |
164 "PrivateServerId" |
165 "PrivateServerOwnerId" |
166 "Workspace "=> Some(Err(LuaError::RuntimeError("Cannot set read only property.".into()))),
167 _ => None
168 }
169 }
170
171 fn clone(self: &RwLockReadGuard<'_, Self>, _: &Lua, _: &WeakManagedInstance) -> LuaResult<Self> {
172 Err(LuaError::RuntimeError("Cannot clone DataModelComponent".into()))
173 }
174
175 fn new(_ptr: WeakManagedInstance, _class_name: &'static str) -> Self {
176 Self {
177 bind_close: RBXScriptSignal::new(),
178 workspace: (),
179 graphics_quality_change_request: RBXScriptSignal::new(),
180 loaded: RBXScriptSignal::new(),
181 is_loaded: false
182 }
183 }
184}
185
186impl IDataModel for DataModel {
187 fn get_data_model_component(&self) -> RwLockReadGuard<'_,DataModelComponent> {
188 self.data_model.read().unwrap()
189 }
190
191 fn get_data_model_component_mut(&self) -> RwLockWriteGuard<'_,DataModelComponent> {
192 self.data_model.write().unwrap()
193 }
194}
195impl dyn IDataModel {
196 pub fn bind_to_close(&self, lua: &Lua, func: LuaFunction) -> LuaResult<()> {
197 let read = self.get_data_model_component();
198 read.bind_close.write().once(lua, func, Synchronized)?;
199 Ok(())
200 }
201 pub fn is_loaded(&self) -> bool {
202 self.get_data_model_component().is_loaded
203 }
204 pub fn fire_loaded(&self, lua: &Lua) -> LuaResult<()> {
205 let mut write = self.get_data_model_component_mut();
206 write.is_loaded = true;
207 write.loaded.write().fire(lua, ())
208 }
209}