@@ -5,7 +5,7 @@ use clap::parser::ValueSource;
5
5
use clap:: Arg ;
6
6
use clap:: ArgAction :: Set ;
7
7
use fs_err as fs;
8
- use spacetimedb_codegen:: { generate, Csharp , Lang , OutputFile , Rust , TypeScript , AUTO_GENERATED_PREFIX } ;
8
+ use spacetimedb_codegen:: { generate, Csharp , Lang , OutputFile , Rust , TypeScript , UnrealCpp , AUTO_GENERATED_PREFIX } ;
9
9
use spacetimedb_lib:: de:: serde:: DeserializeWrapper ;
10
10
use spacetimedb_lib:: { sats, RawModuleDef } ;
11
11
use spacetimedb_schema;
@@ -25,7 +25,7 @@ use std::io::Read;
25
25
pub fn cli ( ) -> clap:: Command {
26
26
clap:: Command :: new ( "generate" )
27
27
. about ( "Generate client files for a spacetime module." )
28
- . override_usage ( "spacetime generate --lang <LANG> --out-dir <DIR> [--project-path <DIR> | --bin-path <PATH>]" )
28
+ . override_usage ( "spacetime generate --lang <LANG> --out-dir <DIR> [--project-path <DIR> | --bin-path <PATH> | --module-name <MODULE_NAME> | --uproject-dir <DIR> ]" )
29
29
. arg (
30
30
Arg :: new ( "wasm_file" )
31
31
. value_parser ( clap:: value_parser!( PathBuf ) )
@@ -57,17 +57,32 @@ pub fn cli() -> clap::Command {
57
57
. arg (
58
58
Arg :: new ( "out_dir" )
59
59
. value_parser ( clap:: value_parser!( PathBuf ) )
60
- . required ( true )
61
60
. long ( "out-dir" )
62
61
. short ( 'o' )
63
- . help ( "The system path (absolute or relative) to the generate output directory" ) ,
62
+ . help ( "The system path (absolute or relative) to the generate output directory" )
63
+ . required_if_eq ( "lang" , "rust" )
64
+ . required_if_eq ( "lang" , "csharp" )
65
+ . required_if_eq ( "lang" , "typescript" ) ,
66
+ )
67
+ . arg (
68
+ Arg :: new ( "uproject_dir" )
69
+ . value_parser ( clap:: value_parser!( PathBuf ) )
70
+ . long ( "uproject-dir" )
71
+ . help ( "Path to the Unreal project directory, replaces --out-dir for Unreal generation (only used with --lang unrealcpp)" )
72
+ . required_if_eq ( "lang" , "unrealcpp" )
64
73
)
65
74
. arg (
66
75
Arg :: new ( "namespace" )
67
76
. default_value ( "SpacetimeDB.Types" )
68
77
. long ( "namespace" )
69
78
. help ( "The namespace that should be used" ) ,
70
79
)
80
+ . arg (
81
+ Arg :: new ( "module_name" )
82
+ . long ( "module-name" )
83
+ . help ( "The module name that should be used for DLL export macros (required for lang unrealcpp)" )
84
+ . required_if_eq ( "lang" , "unrealcpp" )
85
+ )
71
86
. arg (
72
87
Arg :: new ( "lang" )
73
88
. required ( true )
@@ -86,6 +101,11 @@ pub fn cli() -> clap::Command {
86
101
)
87
102
. arg ( common_args:: yes ( ) )
88
103
. after_help ( "Run `spacetime help publish` for more detailed information." )
104
+ . group (
105
+ clap:: ArgGroup :: new ( "output_dir" )
106
+ . args ( [ "out_dir" , "uproject_dir" ] )
107
+ . required ( true )
108
+ )
89
109
}
90
110
91
111
pub async fn exec ( config : Config , args : & clap:: ArgMatches ) -> anyhow:: Result < ( ) > {
@@ -101,16 +121,21 @@ pub async fn exec_ex(
101
121
let project_path = args. get_one :: < PathBuf > ( "project_path" ) . unwrap ( ) ;
102
122
let wasm_file = args. get_one :: < PathBuf > ( "wasm_file" ) . cloned ( ) ;
103
123
let json_module = args. get_many :: < PathBuf > ( "json_module" ) ;
104
- let out_dir = args. get_one :: < PathBuf > ( "out_dir" ) . unwrap ( ) ;
105
124
let lang = * args. get_one :: < Language > ( "lang" ) . unwrap ( ) ;
106
125
let namespace = args. get_one :: < String > ( "namespace" ) . unwrap ( ) ;
126
+ let module_name = args. get_one :: < String > ( "module_name" ) ;
107
127
let force = args. get_flag ( "force" ) ;
108
128
let build_options = args. get_one :: < String > ( "build_options" ) . unwrap ( ) ;
109
129
110
130
if args. value_source ( "namespace" ) == Some ( ValueSource :: CommandLine ) && lang != Language :: Csharp {
111
131
return Err ( anyhow:: anyhow!( "--namespace is only supported with --lang csharp" ) ) ;
112
132
}
113
133
134
+ let out_dir = args
135
+ . get_one :: < PathBuf > ( "out_dir" )
136
+ . or_else ( || args. get_one :: < PathBuf > ( "uproject_dir" ) )
137
+ . unwrap ( ) ;
138
+
114
139
let module: ModuleDef = if let Some ( mut json_module) = json_module {
115
140
let DeserializeWrapper :: < RawModuleDef > ( module) = if let Some ( path) = json_module. next ( ) {
116
141
serde_json:: from_slice ( & fs:: read ( path) ?) ?
@@ -136,11 +161,19 @@ pub async fn exec_ex(
136
161
let mut paths = BTreeSet :: new ( ) ;
137
162
138
163
let csharp_lang;
164
+ let unreal_cpp_lang;
139
165
let gen_lang = match lang {
140
166
Language :: Csharp => {
141
167
csharp_lang = Csharp { namespace } ;
142
168
& csharp_lang as & dyn Lang
143
169
}
170
+ Language :: UnrealCpp => {
171
+ unreal_cpp_lang = UnrealCpp {
172
+ module_name : module_name. as_ref ( ) . unwrap ( ) ,
173
+ uproject_dir : out_dir,
174
+ } ;
175
+ & unreal_cpp_lang as & dyn Lang
176
+ }
144
177
Language :: Rust => & Rust ,
145
178
Language :: TypeScript => & TypeScript ,
146
179
} ;
@@ -156,9 +189,15 @@ pub async fn exec_ex(
156
189
paths. insert ( path) ;
157
190
}
158
191
192
+ // For Unreal, we want to clean up just the module directory, not the entire uproject directory tree.
193
+ let cleanup_root = match lang {
194
+ Language :: UnrealCpp => out_dir. join ( "Source" ) . join ( module_name. as_ref ( ) . unwrap ( ) ) ,
195
+ _ => out_dir. clone ( ) ,
196
+ } ;
197
+
159
198
// TODO: We should probably just delete all generated files before we generate any, rather than selectively deleting some afterward.
160
199
let mut auto_generated_buf: [ u8 ; AUTO_GENERATED_PREFIX . len ( ) ] = [ 0 ; AUTO_GENERATED_PREFIX . len ( ) ] ;
161
- let files_to_delete = walkdir:: WalkDir :: new ( out_dir )
200
+ let files_to_delete = walkdir:: WalkDir :: new ( & cleanup_root )
162
201
. into_iter ( )
163
202
. map ( |entry_result| {
164
203
let entry = entry_result?;
@@ -213,17 +252,19 @@ pub enum Language {
213
252
Csharp ,
214
253
TypeScript ,
215
254
Rust ,
255
+ UnrealCpp ,
216
256
}
217
257
218
258
impl clap:: ValueEnum for Language {
219
259
fn value_variants < ' a > ( ) -> & ' a [ Self ] {
220
- & [ Self :: Csharp , Self :: TypeScript , Self :: Rust ]
260
+ & [ Self :: Csharp , Self :: TypeScript , Self :: Rust , Self :: UnrealCpp ]
221
261
}
222
262
fn to_possible_value ( & self ) -> Option < PossibleValue > {
223
263
Some ( match self {
224
264
Self :: Csharp => clap:: builder:: PossibleValue :: new ( "csharp" ) . aliases ( [ "c#" , "cs" ] ) ,
225
265
Self :: TypeScript => clap:: builder:: PossibleValue :: new ( "typescript" ) . aliases ( [ "ts" , "TS" ] ) ,
226
266
Self :: Rust => clap:: builder:: PossibleValue :: new ( "rust" ) . aliases ( [ "rs" , "RS" ] ) ,
267
+ Self :: UnrealCpp => PossibleValue :: new ( "unrealcpp" ) . aliases ( [ "uecpp" , "ue5cpp" , "unreal" ] ) ,
227
268
} )
228
269
}
229
270
}
@@ -236,6 +277,9 @@ impl Language {
236
277
Language :: TypeScript => {
237
278
// TODO: implement formatting.
238
279
}
280
+ Language :: UnrealCpp => {
281
+ // TODO: implement formatting.
282
+ }
239
283
}
240
284
241
285
Ok ( ( ) )
0 commit comments