mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-04-23 14:15:24 +00:00
Better default project, including minimal property types
This commit is contained in:
@@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
* Fixed `cargo init` giving unexpected results by upgrading to `rbx_dom_weak` 1.1.0
|
* Fixed `cargo init` giving unexpected results by upgrading to `rbx_dom_weak` 1.1.0
|
||||||
|
* Updated default place file:
|
||||||
|
* Improved default properties to be closer to Studio's built-in 'Baseplate' template
|
||||||
|
* Added a baseplate to the project file (Thanks, [@AmaranthineCodices](https://github.com/AmaranthineCodices/)!)
|
||||||
|
|
||||||
## [0.5.0 Alpha 5](https://github.com/LPGhatguy/rojo/releases/tag/v0.5.0-alpha.5) (March 1, 2019)
|
## [0.5.0 Alpha 5](https://github.com/LPGhatguy/rojo/releases/tag/v0.5.0-alpha.5) (March 1, 2019)
|
||||||
* Upgraded core dependencies, which improves compatibility for lots of instance types
|
* Upgraded core dependencies, which improves compatibility for lots of instance types
|
||||||
|
|||||||
66
server/assets/place.project.json
Normal file
66
server/assets/place.project.json
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
{
|
||||||
|
"name": "[placeholder]",
|
||||||
|
"tree": {
|
||||||
|
"$className": "DataModel",
|
||||||
|
"HttpService": {
|
||||||
|
"$className": "HttpService",
|
||||||
|
"$properties": {
|
||||||
|
"HttpEnabled": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Lighting": {
|
||||||
|
"$className": "Lighting",
|
||||||
|
"$properties": {
|
||||||
|
"Ambient": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"Brightness": 2,
|
||||||
|
"GlobalShadows": true,
|
||||||
|
"Outlines": false,
|
||||||
|
"Technology": "Voxel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ReplicatedStorage": {
|
||||||
|
"$className": "ReplicatedStorage",
|
||||||
|
"Source": {
|
||||||
|
"$path": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"SoundService": {
|
||||||
|
"$className": "SoundService",
|
||||||
|
"$properties": {
|
||||||
|
"RespectFilteringEnabled": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Workspace": {
|
||||||
|
"$className": "Workspace",
|
||||||
|
"$properties": {
|
||||||
|
"FilteringEnabled": true
|
||||||
|
},
|
||||||
|
"Baseplate": {
|
||||||
|
"$className": "Part",
|
||||||
|
"$properties": {
|
||||||
|
"Anchored": true,
|
||||||
|
"Color": [
|
||||||
|
0.38823,
|
||||||
|
0.37254,
|
||||||
|
0.38823
|
||||||
|
],
|
||||||
|
"Locked": true,
|
||||||
|
"Position": [
|
||||||
|
0,
|
||||||
|
-10,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"Size": [
|
||||||
|
512,
|
||||||
|
20,
|
||||||
|
512
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,9 +8,11 @@ use std::{
|
|||||||
|
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use failure::Fail;
|
use failure::Fail;
|
||||||
use maplit::hashmap;
|
|
||||||
use rbx_dom_weak::{UnresolvedRbxValue, RbxValue};
|
use rbx_dom_weak::{UnresolvedRbxValue, RbxValue};
|
||||||
use serde_derive::{Serialize, Deserialize};
|
use serde_derive::{Serialize, Deserialize};
|
||||||
|
use serde::{Serialize, Serializer};
|
||||||
|
|
||||||
|
static DEFAULT_PLACE: &'static str = include_str!("../assets/place.project.json");
|
||||||
|
|
||||||
pub static PROJECT_FILENAME: &'static str = "default.project.json";
|
pub static PROJECT_FILENAME: &'static str = "default.project.json";
|
||||||
pub static COMPAT_PROJECT_FILENAME: &'static str = "roblox-project.json";
|
pub static COMPAT_PROJECT_FILENAME: &'static str = "roblox-project.json";
|
||||||
@@ -55,6 +57,74 @@ impl SourceProject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An alternative serializer for `UnresolvedRbxValue` that uses the minimum
|
||||||
|
/// representation of the value.
|
||||||
|
///
|
||||||
|
/// For example, the default Serialize impl might give you:
|
||||||
|
///
|
||||||
|
/// ```json
|
||||||
|
/// {
|
||||||
|
/// "Type": "Bool",
|
||||||
|
/// "Value": true
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// But in reality, users are expected to write just:
|
||||||
|
///
|
||||||
|
/// ```json
|
||||||
|
/// true
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// This holds true for other values that might be ambiguous or just have more
|
||||||
|
/// complicated representations like enums.
|
||||||
|
fn serialize_unresolved_minimal<S>(value: &UnresolvedRbxValue, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where S: Serializer
|
||||||
|
{
|
||||||
|
match value {
|
||||||
|
UnresolvedRbxValue::Ambiguous(_) => value.serialize(serializer),
|
||||||
|
UnresolvedRbxValue::Concrete(concrete) => {
|
||||||
|
match concrete {
|
||||||
|
RbxValue::Bool { value } => value.serialize(serializer),
|
||||||
|
RbxValue::CFrame { value } => value.serialize(serializer),
|
||||||
|
RbxValue::Color3 { value } => value.serialize(serializer),
|
||||||
|
RbxValue::Color3uint8 { value } => value.serialize(serializer),
|
||||||
|
RbxValue::Content { value } => value.serialize(serializer),
|
||||||
|
RbxValue::Enum { value } => value.serialize(serializer),
|
||||||
|
RbxValue::Float32 { value } => value.serialize(serializer),
|
||||||
|
RbxValue::Int32 { value } => value.serialize(serializer),
|
||||||
|
RbxValue::String { value } => value.serialize(serializer),
|
||||||
|
RbxValue::UDim { value } => value.serialize(serializer),
|
||||||
|
RbxValue::UDim2 { value } => value.serialize(serializer),
|
||||||
|
RbxValue::Vector2 { value } => value.serialize(serializer),
|
||||||
|
RbxValue::Vector2int16 { value } => value.serialize(serializer),
|
||||||
|
RbxValue::Vector3 { value } => value.serialize(serializer),
|
||||||
|
RbxValue::Vector3int16 { value } => value.serialize(serializer),
|
||||||
|
_ => concrete.serialize(serializer),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A wrapper around serialize_unresolved_minimal that handles the HashMap case.
|
||||||
|
fn serialize_unresolved_map<S>(value: &HashMap<String, UnresolvedRbxValue>, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where S: Serializer
|
||||||
|
{
|
||||||
|
use serde::ser::SerializeMap;
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
struct Minimal<'a>(
|
||||||
|
#[serde(serialize_with = "serialize_unresolved_minimal")]
|
||||||
|
&'a UnresolvedRbxValue
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut map = serializer.serialize_map(Some(value.len()))?;
|
||||||
|
for (k, v) in value {
|
||||||
|
map.serialize_key(k)?;
|
||||||
|
map.serialize_value(&Minimal(v))?;
|
||||||
|
}
|
||||||
|
map.end()
|
||||||
|
}
|
||||||
|
|
||||||
/// Similar to SourceProject, the structure of nodes in the project tree is
|
/// Similar to SourceProject, the structure of nodes in the project tree is
|
||||||
/// slightly different on-disk than how we want to handle them in the rest of
|
/// slightly different on-disk than how we want to handle them in the rest of
|
||||||
/// Rojo.
|
/// Rojo.
|
||||||
@@ -63,7 +133,12 @@ struct SourceProjectNode {
|
|||||||
#[serde(rename = "$className", skip_serializing_if = "Option::is_none")]
|
#[serde(rename = "$className", skip_serializing_if = "Option::is_none")]
|
||||||
class_name: Option<String>,
|
class_name: Option<String>,
|
||||||
|
|
||||||
#[serde(rename = "$properties", default = "HashMap::new", skip_serializing_if = "HashMap::is_empty")]
|
#[serde(
|
||||||
|
rename = "$properties",
|
||||||
|
default = "HashMap::new",
|
||||||
|
skip_serializing_if = "HashMap::is_empty",
|
||||||
|
serialize_with = "serialize_unresolved_map",
|
||||||
|
)]
|
||||||
properties: HashMap<String, UnresolvedRbxValue>,
|
properties: HashMap<String, UnresolvedRbxValue>,
|
||||||
|
|
||||||
#[serde(rename = "$ignoreUnknownInstances", skip_serializing_if = "Option::is_none")]
|
#[serde(rename = "$ignoreUnknownInstances", skip_serializing_if = "Option::is_none")]
|
||||||
@@ -162,6 +237,7 @@ pub enum ProjectInitError {
|
|||||||
AlreadyExists(PathBuf),
|
AlreadyExists(PathBuf),
|
||||||
IoError(#[fail(cause)] io::Error),
|
IoError(#[fail(cause)] io::Error),
|
||||||
SaveError(#[fail(cause)] ProjectSaveError),
|
SaveError(#[fail(cause)] ProjectSaveError),
|
||||||
|
JsonError(#[fail(cause)] serde_json::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for ProjectInitError {
|
impl fmt::Display for ProjectInitError {
|
||||||
@@ -170,6 +246,7 @@ impl fmt::Display for ProjectInitError {
|
|||||||
ProjectInitError::AlreadyExists(path) => write!(output, "Path {} already exists", path.display()),
|
ProjectInitError::AlreadyExists(path) => write!(output, "Path {} already exists", path.display()),
|
||||||
ProjectInitError::IoError(inner) => write!(output, "IO error: {}", inner),
|
ProjectInitError::IoError(inner) => write!(output, "IO error: {}", inner),
|
||||||
ProjectInitError::SaveError(inner) => write!(output, "{}", inner),
|
ProjectInitError::SaveError(inner) => write!(output, "{}", inner),
|
||||||
|
ProjectInitError::JsonError(inner) => write!(output, "{}", inner),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -259,47 +336,16 @@ pub struct Project {
|
|||||||
impl Project {
|
impl Project {
|
||||||
pub fn init_place(project_fuzzy_path: &Path) -> Result<PathBuf, ProjectInitError> {
|
pub fn init_place(project_fuzzy_path: &Path) -> Result<PathBuf, ProjectInitError> {
|
||||||
let project_path = Project::init_pick_path(project_fuzzy_path)?;
|
let project_path = Project::init_pick_path(project_fuzzy_path)?;
|
||||||
let project_folder_path = project_path.parent().unwrap();
|
|
||||||
let project_name = if project_fuzzy_path == project_path {
|
let project_name = if project_fuzzy_path == project_path {
|
||||||
project_fuzzy_path.parent().unwrap().file_name().unwrap().to_str().unwrap()
|
project_fuzzy_path.parent().unwrap().file_name().unwrap().to_str().unwrap()
|
||||||
} else {
|
} else {
|
||||||
project_fuzzy_path.file_name().unwrap().to_str().unwrap()
|
project_fuzzy_path.file_name().unwrap().to_str().unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
let tree = ProjectNode {
|
let mut project = Project::load_from_str(DEFAULT_PLACE, &project_path)
|
||||||
class_name: Some(String::from("DataModel")),
|
.map_err(ProjectInitError::JsonError)?;
|
||||||
children: hashmap! {
|
|
||||||
String::from("ReplicatedStorage") => ProjectNode {
|
|
||||||
class_name: Some(String::from("ReplicatedStorage")),
|
|
||||||
children: hashmap! {
|
|
||||||
String::from("Source") => ProjectNode {
|
|
||||||
path: Some(project_folder_path.join("src")),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
},
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
String::from("HttpService") => ProjectNode {
|
|
||||||
class_name: Some(String::from("HttpService")),
|
|
||||||
properties: hashmap! {
|
|
||||||
String::from("HttpEnabled") => RbxValue::Bool {
|
|
||||||
value: true,
|
|
||||||
}.into(),
|
|
||||||
},
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
},
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
let project = Project {
|
project.name = project_name.to_owned();
|
||||||
name: project_name.to_string(),
|
|
||||||
tree,
|
|
||||||
plugins: Vec::new(),
|
|
||||||
serve_port: None,
|
|
||||||
serve_place_ids: None,
|
|
||||||
file_location: project_path.clone(),
|
|
||||||
};
|
|
||||||
|
|
||||||
project.save()
|
project.save()
|
||||||
.map_err(ProjectInitError::SaveError)?;
|
.map_err(ProjectInitError::SaveError)?;
|
||||||
@@ -387,6 +433,12 @@ impl Project {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn load_from_str(contents: &str, project_file_location: &Path) -> Result<Project, serde_json::Error> {
|
||||||
|
let parsed: SourceProject = serde_json::from_str(&contents)?;
|
||||||
|
|
||||||
|
Ok(parsed.into_project(project_file_location))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn load_fuzzy(fuzzy_project_location: &Path) -> Result<Project, ProjectLoadFuzzyError> {
|
pub fn load_fuzzy(fuzzy_project_location: &Path) -> Result<Project, ProjectLoadFuzzyError> {
|
||||||
let project_path = Self::locate(fuzzy_project_location)
|
let project_path = Self::locate(fuzzy_project_location)
|
||||||
.ok_or(ProjectLoadFuzzyError::NotFound)?;
|
.ok_or(ProjectLoadFuzzyError::NotFound)?;
|
||||||
|
|||||||
Reference in New Issue
Block a user