1#[allow(unused_imports)]
9use alloc::collections::BTreeMap;
10
11#[allow(unused_imports)]
12use core::marker::PhantomData;
13use jacquard_common::{BosStr, CowStr, DefaultStr, FromStaticStr};
14
15#[allow(unused_imports)]
16use jacquard_common::deps::codegen::unicode_segmentation::UnicodeSegmentation;
17use jacquard_common::deps::smol_str::SmolStr;
18use jacquard_common::types::collection::{Collection, RecordError};
19use jacquard_common::types::string::{AtUri, Cid, Datetime};
20use jacquard_common::types::uri::{RecordUri, UriError};
21use jacquard_common::types::value::Data;
22use jacquard_common::xrpc::XrpcResp;
23use jacquard_derive::{IntoStatic, lexicon};
24use jacquard_lexicon::lexicon::LexiconDoc;
25use jacquard_lexicon::schema::LexiconSchema;
26
27#[allow(unused_imports)]
28use jacquard_lexicon::validation::{ConstraintError, ValidationPath};
29use serde::{Deserialize, Serialize};
30#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
33#[serde(
34 rename_all = "camelCase",
35 rename = "net.anisota.player.state",
36 tag = "$type",
37 bound(deserialize = "S: Deserialize<'de> + BosStr")
38)]
39pub struct State<S: BosStr = DefaultStr> {
40 #[serde(skip_serializing_if = "Option::is_none")]
42 pub active_blocks_intention_daily: Option<S>,
43 #[serde(skip_serializing_if = "Option::is_none")]
45 pub activity_intention_consuming7d: Option<S>,
46 #[serde(skip_serializing_if = "Option::is_none")]
48 pub activity_intention_creating7d: Option<S>,
49 #[serde(skip_serializing_if = "Option::is_none")]
51 pub activity_intention_total7d: Option<S>,
52 #[serde(skip_serializing_if = "Option::is_none")]
54 pub activity_intention_x: Option<S>,
55 #[serde(skip_serializing_if = "Option::is_none")]
57 pub activity_intention_y: Option<S>,
58 #[serde(skip_serializing_if = "Option::is_none")]
60 pub current_light: Option<S>,
61 #[serde(skip_serializing_if = "Option::is_none")]
63 pub current_stamina: Option<S>,
64 #[serde(skip_serializing_if = "Option::is_none")]
66 pub equipped: Option<Data<S>>,
67 #[serde(skip_serializing_if = "Option::is_none")]
69 pub last_session_start: Option<Datetime>,
70 #[serde(skip_serializing_if = "Option::is_none")]
72 pub light_drain_active: Option<bool>,
73 #[serde(skip_serializing_if = "Option::is_none")]
75 pub slot_capacity: Option<Data<S>>,
76 #[serde(skip_serializing_if = "Option::is_none")]
78 pub starter_items_granted: Option<bool>,
79 #[serde(skip_serializing_if = "Option::is_none")]
81 pub trigger_source: Option<S>,
82 #[serde(skip_serializing_if = "Option::is_none")]
84 pub tutorial_completed_at: Option<Datetime>,
85 pub updated_at: Datetime,
87 #[serde(flatten, default, skip_serializing_if = "Option::is_none")]
88 pub extra_data: Option<BTreeMap<SmolStr, Data<S>>>,
89}
90
91#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
94#[serde(rename_all = "camelCase")]
95pub struct StateGetRecordOutput<S: BosStr = DefaultStr> {
96 #[serde(skip_serializing_if = "Option::is_none")]
97 pub cid: Option<Cid<S>>,
98 pub uri: AtUri<S>,
99 pub value: State<S>,
100}
101
102impl<S: BosStr> State<S> {
103 pub fn uri(uri: S) -> Result<RecordUri<S, StateRecord>, UriError> {
104 RecordUri::try_from_uri(AtUri::new(uri)?)
105 }
106}
107
108#[derive(Debug, Serialize, Deserialize)]
111pub struct StateRecord;
112impl XrpcResp for StateRecord {
113 const NSID: &'static str = "net.anisota.player.state";
114 const ENCODING: &'static str = "application/json";
115 type Output<S: BosStr> = StateGetRecordOutput<S>;
116 type Err = RecordError;
117}
118
119impl<S: BosStr> From<StateGetRecordOutput<S>> for State<S> {
120 fn from(output: StateGetRecordOutput<S>) -> Self {
121 output.value
122 }
123}
124
125impl<S: BosStr> Collection for State<S> {
126 const NSID: &'static str = "net.anisota.player.state";
127 type Record = StateRecord;
128}
129
130impl Collection for StateRecord {
131 const NSID: &'static str = "net.anisota.player.state";
132 type Record = StateRecord;
133}
134
135impl<S: BosStr> LexiconSchema for State<S> {
136 fn nsid() -> &'static str {
137 "net.anisota.player.state"
138 }
139 fn def_name() -> &'static str {
140 "main"
141 }
142 fn lexicon_doc() -> LexiconDoc<'static> {
143 lexicon_doc_net_anisota_player_state()
144 }
145 fn validate(&self) -> Result<(), ConstraintError> {
146 Ok(())
147 }
148}
149
150pub mod state_state {
151
152 pub use crate::builder_types::{IsSet, IsUnset, Set, Unset};
153 #[allow(unused)]
154 use ::core::marker::PhantomData;
155 mod sealed {
156 pub trait Sealed {}
157 }
158 pub trait State: sealed::Sealed {
160 type UpdatedAt;
161 }
162 pub struct Empty(());
164 impl sealed::Sealed for Empty {}
165 impl State for Empty {
166 type UpdatedAt = Unset;
167 }
168 pub struct SetUpdatedAt<St: State = Empty>(PhantomData<fn() -> St>);
170 impl<St: State> sealed::Sealed for SetUpdatedAt<St> {}
171 impl<St: State> State for SetUpdatedAt<St> {
172 type UpdatedAt = Set<members::updated_at>;
173 }
174 #[allow(non_camel_case_types)]
176 pub mod members {
177 pub struct updated_at(());
179 }
180}
181
182pub struct StateBuilder<St: state_state::State, S: BosStr = DefaultStr> {
184 _state: PhantomData<fn() -> St>,
185 _fields: (
186 Option<S>,
187 Option<S>,
188 Option<S>,
189 Option<S>,
190 Option<S>,
191 Option<S>,
192 Option<S>,
193 Option<S>,
194 Option<Data<S>>,
195 Option<Datetime>,
196 Option<bool>,
197 Option<Data<S>>,
198 Option<bool>,
199 Option<S>,
200 Option<Datetime>,
201 Option<Datetime>,
202 ),
203 _type: PhantomData<fn() -> S>,
204}
205
206impl State<DefaultStr> {
207 pub fn new() -> StateBuilder<state_state::Empty, DefaultStr> {
209 StateBuilder::new()
210 }
211}
212
213impl<S: BosStr> State<S> {
214 pub fn builder() -> StateBuilder<state_state::Empty, S> {
216 StateBuilder::builder()
217 }
218}
219
220impl StateBuilder<state_state::Empty, DefaultStr> {
221 pub fn new() -> Self {
223 StateBuilder {
224 _state: PhantomData,
225 _fields: (
226 None, None, None, None, None, None, None, None, None, None, None, None, None, None,
227 None, None,
228 ),
229 _type: PhantomData,
230 }
231 }
232}
233
234impl<S: BosStr> StateBuilder<state_state::Empty, S> {
235 pub fn builder() -> Self {
237 StateBuilder {
238 _state: PhantomData,
239 _fields: (
240 None, None, None, None, None, None, None, None, None, None, None, None, None, None,
241 None, None,
242 ),
243 _type: PhantomData,
244 }
245 }
246}
247
248impl<St: state_state::State, S: BosStr> StateBuilder<St, S> {
249 pub fn active_blocks_intention_daily(mut self, value: impl Into<Option<S>>) -> Self {
251 self._fields.0 = value.into();
252 self
253 }
254 pub fn maybe_active_blocks_intention_daily(mut self, value: Option<S>) -> Self {
256 self._fields.0 = value;
257 self
258 }
259}
260
261impl<St: state_state::State, S: BosStr> StateBuilder<St, S> {
262 pub fn activity_intention_consuming7d(mut self, value: impl Into<Option<S>>) -> Self {
264 self._fields.1 = value.into();
265 self
266 }
267 pub fn maybe_activity_intention_consuming7d(mut self, value: Option<S>) -> Self {
269 self._fields.1 = value;
270 self
271 }
272}
273
274impl<St: state_state::State, S: BosStr> StateBuilder<St, S> {
275 pub fn activity_intention_creating7d(mut self, value: impl Into<Option<S>>) -> Self {
277 self._fields.2 = value.into();
278 self
279 }
280 pub fn maybe_activity_intention_creating7d(mut self, value: Option<S>) -> Self {
282 self._fields.2 = value;
283 self
284 }
285}
286
287impl<St: state_state::State, S: BosStr> StateBuilder<St, S> {
288 pub fn activity_intention_total7d(mut self, value: impl Into<Option<S>>) -> Self {
290 self._fields.3 = value.into();
291 self
292 }
293 pub fn maybe_activity_intention_total7d(mut self, value: Option<S>) -> Self {
295 self._fields.3 = value;
296 self
297 }
298}
299
300impl<St: state_state::State, S: BosStr> StateBuilder<St, S> {
301 pub fn activity_intention_x(mut self, value: impl Into<Option<S>>) -> Self {
303 self._fields.4 = value.into();
304 self
305 }
306 pub fn maybe_activity_intention_x(mut self, value: Option<S>) -> Self {
308 self._fields.4 = value;
309 self
310 }
311}
312
313impl<St: state_state::State, S: BosStr> StateBuilder<St, S> {
314 pub fn activity_intention_y(mut self, value: impl Into<Option<S>>) -> Self {
316 self._fields.5 = value.into();
317 self
318 }
319 pub fn maybe_activity_intention_y(mut self, value: Option<S>) -> Self {
321 self._fields.5 = value;
322 self
323 }
324}
325
326impl<St: state_state::State, S: BosStr> StateBuilder<St, S> {
327 pub fn current_light(mut self, value: impl Into<Option<S>>) -> Self {
329 self._fields.6 = value.into();
330 self
331 }
332 pub fn maybe_current_light(mut self, value: Option<S>) -> Self {
334 self._fields.6 = value;
335 self
336 }
337}
338
339impl<St: state_state::State, S: BosStr> StateBuilder<St, S> {
340 pub fn current_stamina(mut self, value: impl Into<Option<S>>) -> Self {
342 self._fields.7 = value.into();
343 self
344 }
345 pub fn maybe_current_stamina(mut self, value: Option<S>) -> Self {
347 self._fields.7 = value;
348 self
349 }
350}
351
352impl<St: state_state::State, S: BosStr> StateBuilder<St, S> {
353 pub fn equipped(mut self, value: impl Into<Option<Data<S>>>) -> Self {
355 self._fields.8 = value.into();
356 self
357 }
358 pub fn maybe_equipped(mut self, value: Option<Data<S>>) -> Self {
360 self._fields.8 = value;
361 self
362 }
363}
364
365impl<St: state_state::State, S: BosStr> StateBuilder<St, S> {
366 pub fn last_session_start(mut self, value: impl Into<Option<Datetime>>) -> Self {
368 self._fields.9 = value.into();
369 self
370 }
371 pub fn maybe_last_session_start(mut self, value: Option<Datetime>) -> Self {
373 self._fields.9 = value;
374 self
375 }
376}
377
378impl<St: state_state::State, S: BosStr> StateBuilder<St, S> {
379 pub fn light_drain_active(mut self, value: impl Into<Option<bool>>) -> Self {
381 self._fields.10 = value.into();
382 self
383 }
384 pub fn maybe_light_drain_active(mut self, value: Option<bool>) -> Self {
386 self._fields.10 = value;
387 self
388 }
389}
390
391impl<St: state_state::State, S: BosStr> StateBuilder<St, S> {
392 pub fn slot_capacity(mut self, value: impl Into<Option<Data<S>>>) -> Self {
394 self._fields.11 = value.into();
395 self
396 }
397 pub fn maybe_slot_capacity(mut self, value: Option<Data<S>>) -> Self {
399 self._fields.11 = value;
400 self
401 }
402}
403
404impl<St: state_state::State, S: BosStr> StateBuilder<St, S> {
405 pub fn starter_items_granted(mut self, value: impl Into<Option<bool>>) -> Self {
407 self._fields.12 = value.into();
408 self
409 }
410 pub fn maybe_starter_items_granted(mut self, value: Option<bool>) -> Self {
412 self._fields.12 = value;
413 self
414 }
415}
416
417impl<St: state_state::State, S: BosStr> StateBuilder<St, S> {
418 pub fn trigger_source(mut self, value: impl Into<Option<S>>) -> Self {
420 self._fields.13 = value.into();
421 self
422 }
423 pub fn maybe_trigger_source(mut self, value: Option<S>) -> Self {
425 self._fields.13 = value;
426 self
427 }
428}
429
430impl<St: state_state::State, S: BosStr> StateBuilder<St, S> {
431 pub fn tutorial_completed_at(mut self, value: impl Into<Option<Datetime>>) -> Self {
433 self._fields.14 = value.into();
434 self
435 }
436 pub fn maybe_tutorial_completed_at(mut self, value: Option<Datetime>) -> Self {
438 self._fields.14 = value;
439 self
440 }
441}
442
443impl<St, S: BosStr> StateBuilder<St, S>
444where
445 St: state_state::State,
446 St::UpdatedAt: state_state::IsUnset,
447{
448 pub fn updated_at(
450 mut self,
451 value: impl Into<Datetime>,
452 ) -> StateBuilder<state_state::SetUpdatedAt<St>, S> {
453 self._fields.15 = Option::Some(value.into());
454 StateBuilder {
455 _state: PhantomData,
456 _fields: self._fields,
457 _type: PhantomData,
458 }
459 }
460}
461
462impl<St, S: BosStr> StateBuilder<St, S>
463where
464 St: state_state::State,
465 St::UpdatedAt: state_state::IsSet,
466{
467 pub fn build(self) -> State<S> {
469 State {
470 active_blocks_intention_daily: self._fields.0,
471 activity_intention_consuming7d: self._fields.1,
472 activity_intention_creating7d: self._fields.2,
473 activity_intention_total7d: self._fields.3,
474 activity_intention_x: self._fields.4,
475 activity_intention_y: self._fields.5,
476 current_light: self._fields.6,
477 current_stamina: self._fields.7,
478 equipped: self._fields.8,
479 last_session_start: self._fields.9,
480 light_drain_active: self._fields.10,
481 slot_capacity: self._fields.11,
482 starter_items_granted: self._fields.12,
483 trigger_source: self._fields.13,
484 tutorial_completed_at: self._fields.14,
485 updated_at: self._fields.15.unwrap(),
486 extra_data: Default::default(),
487 }
488 }
489 pub fn build_with_data(self, extra_data: BTreeMap<SmolStr, Data<S>>) -> State<S> {
491 State {
492 active_blocks_intention_daily: self._fields.0,
493 activity_intention_consuming7d: self._fields.1,
494 activity_intention_creating7d: self._fields.2,
495 activity_intention_total7d: self._fields.3,
496 activity_intention_x: self._fields.4,
497 activity_intention_y: self._fields.5,
498 current_light: self._fields.6,
499 current_stamina: self._fields.7,
500 equipped: self._fields.8,
501 last_session_start: self._fields.9,
502 light_drain_active: self._fields.10,
503 slot_capacity: self._fields.11,
504 starter_items_granted: self._fields.12,
505 trigger_source: self._fields.13,
506 tutorial_completed_at: self._fields.14,
507 updated_at: self._fields.15.unwrap(),
508 extra_data: Some(extra_data),
509 }
510 }
511}
512
513fn lexicon_doc_net_anisota_player_state() -> LexiconDoc<'static> {
514 use alloc::collections::BTreeMap;
515 #[allow(unused_imports)]
516 use jacquard_common::{CowStr, deps::smol_str::SmolStr, types::blob::MimeType};
517 use jacquard_lexicon::lexicon::*;
518 LexiconDoc {
519 lexicon: Lexicon::Lexicon1,
520 id: CowStr::new_static("net.anisota.player.state"),
521 defs: {
522 let mut map = BTreeMap::new();
523 map.insert(
524 SmolStr::new_static("main"),
525 LexUserType::Record(LexRecord {
526 description: Some(
527 CowStr::new_static(
528 "Ephemeral player state for cross-device sync. Singleton record (rkey: self), overwritten via putRecord.",
529 ),
530 ),
531 key: Some(CowStr::new_static("any")),
532 record: LexRecordRecord::Object(LexObject {
533 required: Some(vec![SmolStr::new_static("updatedAt")]),
534 properties: {
535 #[allow(unused_mut)]
536 let mut map = BTreeMap::new();
537 map.insert(
538 SmolStr::new_static("activeBlocksIntentionDaily"),
539 LexObjectProperty::String(LexString {
540 description: Some(
541 CowStr::new_static(
542 "Target active blocks per day (decimal string, e.g. '6')",
543 ),
544 ),
545 ..Default::default()
546 }),
547 );
548 map.insert(
549 SmolStr::new_static("activityIntentionConsuming7d"),
550 LexObjectProperty::String(LexString {
551 description: Some(
552 CowStr::new_static(
553 "Deprecated: use activityIntentionTotal7d. Target weekly consuming count.",
554 ),
555 ),
556 ..Default::default()
557 }),
558 );
559 map.insert(
560 SmolStr::new_static("activityIntentionCreating7d"),
561 LexObjectProperty::String(LexString {
562 description: Some(
563 CowStr::new_static(
564 "Deprecated: use activityIntentionTotal7d. Target weekly creating count.",
565 ),
566 ),
567 ..Default::default()
568 }),
569 );
570 map.insert(
571 SmolStr::new_static("activityIntentionTotal7d"),
572 LexObjectProperty::String(LexString {
573 description: Some(
574 CowStr::new_static(
575 "Target total weekly activity count, sum of all actions (decimal string, e.g. '500')",
576 ),
577 ),
578 ..Default::default()
579 }),
580 );
581 map.insert(
582 SmolStr::new_static("activityIntentionX"),
583 LexObjectProperty::String(LexString {
584 description: Some(
585 CowStr::new_static(
586 "Activity style intention X position as grid percentage (0-100, consuming axis)",
587 ),
588 ),
589 ..Default::default()
590 }),
591 );
592 map.insert(
593 SmolStr::new_static("activityIntentionY"),
594 LexObjectProperty::String(LexString {
595 description: Some(
596 CowStr::new_static(
597 "Activity style intention Y position as grid percentage (0-100, creating axis)",
598 ),
599 ),
600 ..Default::default()
601 }),
602 );
603 map.insert(
604 SmolStr::new_static("currentLight"),
605 LexObjectProperty::String(LexString {
606 description: Some(
607 CowStr::new_static(
608 "Current light charge in Wh (decimal string, e.g. '280.0')",
609 ),
610 ),
611 ..Default::default()
612 }),
613 );
614 map.insert(
615 SmolStr::new_static("currentStamina"),
616 LexObjectProperty::String(LexString {
617 description: Some(
618 CowStr::new_static(
619 "Current stamina level (decimal string, e.g. '42.5')",
620 ),
621 ),
622 ..Default::default()
623 }),
624 );
625 map.insert(
626 SmolStr::new_static("equipped"),
627 LexObjectProperty::Unknown(LexUnknown {
628 ..Default::default()
629 }),
630 );
631 map.insert(
632 SmolStr::new_static("lastSessionStart"),
633 LexObjectProperty::String(LexString {
634 description: Some(
635 CowStr::new_static(
636 "When the current session started (for multi-device awareness)",
637 ),
638 ),
639 format: Some(LexStringFormat::Datetime),
640 ..Default::default()
641 }),
642 );
643 map.insert(
644 SmolStr::new_static("lightDrainActive"),
645 LexObjectProperty::Boolean(LexBoolean {
646 ..Default::default()
647 }),
648 );
649 map.insert(
650 SmolStr::new_static("slotCapacity"),
651 LexObjectProperty::Unknown(LexUnknown {
652 ..Default::default()
653 }),
654 );
655 map.insert(
656 SmolStr::new_static("starterItemsGranted"),
657 LexObjectProperty::Boolean(LexBoolean {
658 ..Default::default()
659 }),
660 );
661 map.insert(
662 SmolStr::new_static("triggerSource"),
663 LexObjectProperty::String(LexString {
664 description: Some(
665 CowStr::new_static(
666 "What caused this state snapshot (visibility_hidden, session_end, stamina_depleted, manual)",
667 ),
668 ),
669 ..Default::default()
670 }),
671 );
672 map.insert(
673 SmolStr::new_static("tutorialCompletedAt"),
674 LexObjectProperty::String(LexString {
675 description: Some(
676 CowStr::new_static(
677 "When the player completed (or skipped) the interactive tutorial. Presence of this field means the tutorial is done; absence means it has not been completed.",
678 ),
679 ),
680 format: Some(LexStringFormat::Datetime),
681 ..Default::default()
682 }),
683 );
684 map.insert(
685 SmolStr::new_static("updatedAt"),
686 LexObjectProperty::String(LexString {
687 description: Some(
688 CowStr::new_static("When this state snapshot was taken"),
689 ),
690 format: Some(LexStringFormat::Datetime),
691 ..Default::default()
692 }),
693 );
694 map
695 },
696 ..Default::default()
697 }),
698 ..Default::default()
699 }),
700 );
701 map
702 },
703 ..Default::default()
704 }
705}