Skip to content

Commit 3b02591

Browse files
committed
Merge branch 'main' into dev
2 parents b8ca81c + fd7890d commit 3b02591

3 files changed

Lines changed: 135 additions & 0 deletions

File tree

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
---
2+
title: "Storing Persistant Data on the Player"
3+
description: "Learn how to save and load persistant data using Components"
4+
authors:
5+
- name: "ArcticDev"
6+
url: "https://github.com/ArcticRaven"
7+
- name: "Neil Revin"
8+
url: "https://itsneil.dev/"
9+
---
10+
11+
Here is how to store persistent data using a custom component on a Player.
12+
13+
## Build your Component Class
14+
15+
Creating a custom component class leverages the Component system made with the ECS architecture in mind. For more information on Components, check out the [ECS Guide](../ecs/hytale-ecs-theory.mdx#components).
16+
17+
Start by creating your custom component class. This will be extremely similar to how regular components are created, however we'll setup a custom Codec so the server can translate this data to BSON, or the server's internal json encoder.
18+
19+
<Callout type="info">
20+
Each variable you want to store in your component must have its own Codec field defined in the BuilderCodec.
21+
Since the codec system is lambda based, you provide a setter and getter for each field.
22+
23+
Using complex data types (like Lists, Maps, etc) is possible, but can get tricky.
24+
Refer to the available Codec types in the `Server.jar/com/hypixel/hytale/codec/` package for more information on what types are available.
25+
26+
Note that the 'key' used in the KeyedCodec must start with a Capital Letter, otherwise it may not serialize properly.
27+
</Callout>
28+
29+
```java
30+
public class YourPlayerData implements Component<EntityStore> {
31+
32+
// define some vars!
33+
private int someInteger;
34+
private String someString;
35+
private Map<String, String> someMap;
36+
37+
public static final BuilderCodec<YourPlayerData> CODEC =
38+
BuilderCodec.builder(YourPlayerData.class, YourPlayerData::new)
39+
.addField(new KeyedCodec<>("SomeInteger", Codec.INTEGER),
40+
(data, value) -> data.someInteger = value, // setter
41+
data -> data.someInteger) // getter
42+
.addField(new KeyedCodec<>("SomeString", Codec.STRING),
43+
(data, value) -> data.someString = value, // setter
44+
data -> data.someString) // getter
45+
.addField(new KeyedCodec<>("SomeMap",
46+
new MapCodec<>(Codec.STRING, HashMap::new, false)),
47+
(data, value) -> data.someMap = value, // setter
48+
data -> data.someMap) // getter
49+
.build();
50+
51+
52+
53+
// Getters and Setters are for the purpose of this example omitted.
54+
55+
// constructor
56+
public YourPlayerData() {
57+
this.someInteger = 0;
58+
this.someString = "";
59+
this.someMap = new HashMap<>();
60+
}
61+
62+
// copy constructor for cloning
63+
public YourPlayerData(YourPlayerData clone) {
64+
this.someInteger = clone.someInteger;
65+
this.someString = clone.someString;
66+
this.someMap = clone.someMap;
67+
}
68+
69+
@NullableDecl
70+
@Override
71+
public Component<EntityStore> clone() {
72+
return new YourPlayerData(this);
73+
}
74+
}
75+
```
76+
77+
## Register your Component
78+
Inside your main class's `setup()` method, register your new Component.
79+
80+
```java
81+
public class YourPlugin extends JavaPlugin {
82+
83+
private ComponentType<EntityStore, YourPlayerData> yourPlayerDataComponent;
84+
85+
public YourPlugin(@NonNullDecl JavaPluginInit init) {
86+
super(init);
87+
}
88+
89+
@Override
90+
protected void setup(){
91+
this.yourPlayerDataComponent = this.getEntityStoreRegistry().registerComponent(
92+
YourPlayerData.class,
93+
"YourPlayerDataComponent",
94+
YourPlayerData.CODEC
95+
);
96+
}
97+
98+
public ComponentType<EntityStore, YourPlayerData> getYourPlayerDataComponent() {
99+
return this.yourPlayerDataComponent;
100+
}
101+
}
102+
```
103+
104+
## Using your Data
105+
106+
Your component will be stored within the `Store<EntityStore>` when added to the player. In the provided example,
107+
we'll fetch this data off the player using the `ensureAndGetComponent()` method, which will add the component to
108+
the player if it does not exist.
109+
110+
```java
111+
public class IncompleteCustomCommand extends AbstractPlayerCommand {
112+
113+
public IncompleteCustomCommand() {
114+
super("nope", "don't use this command");
115+
}
116+
117+
@Override
118+
protected void execute(
119+
@NonNullDecl CommandContext commandContext,
120+
@NonNullDecl Store<EntityStore> store,
121+
@NonNullDecl Ref<EntityStore> ref,
122+
@NonNullDecl PlayerRef playerRef,
123+
@NonNullDecl World world
124+
) {
125+
YourPlayerData customData = store.ensureAndGetComponent(ref, YourPlugin.instance().getYourPlayerDataComponent());
126+
127+
// use your data
128+
}
129+
}
130+
```
131+
132+
And that's it! Your data will now be saved and loaded automatically with the player.
133+
134+
## Conclusion
135+
Using custom components to store persistent data on players is a powerful way to maintain state across sessions. By following the steps outlined above, you can easily create, register, and utilize your own data structures within the Hytale modding framework. This approach ensures that your data is seamlessly integrated with the game's existing systems, providing a robust solution for managing player-specific information. Happy modding!
783 KB
Loading
259 KB
Loading

0 commit comments

Comments
 (0)