Skip to content

Commit ccc2ff1

Browse files
cryptobenchclaude
andcommitted
Initial release of HomeEssentials plugin for Hytale
Features: - /sethome [name] - Save locations with custom names - /home [name] - Teleport to saved homes - /delhome <name> - Delete homes - /homes - List all homes - /homehelp - Show help and setup guide - Permission-based home limits (1, 3, 5, unlimited) - 3-second teleport warmup with movement cancellation - Colored chat messages - JSON data storage per player Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
0 parents  commit ccc2ff1

File tree

16 files changed

+1527
-0
lines changed

16 files changed

+1527
-0
lines changed

.gitignore

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Build output
2+
target/
3+
4+
# IDE
5+
.idea/
6+
*.iml
7+
.vscode/
8+
.project
9+
.classpath
10+
.settings/
11+
12+
# OS
13+
.DS_Store
14+
Thumbs.db
15+
16+
# Logs
17+
*.log

CLAUDE.md

Lines changed: 377 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,377 @@
1+
# Hytale Plugin Development Guide
2+
3+
## Overview
4+
This document contains learnings from developing the HomeEssentials plugin for Hytale servers.
5+
6+
## Project Structure
7+
8+
```
9+
plugins/PluginName/
10+
├── src/main/java/com/yourplugin/
11+
│ ├── YourPlugin.java # Main plugin class
12+
│ ├── commands/ # Command classes
13+
│ └── data/ # Data classes
14+
├── src/main/resources/
15+
│ └── manifest.json # Plugin manifest (REQUIRED)
16+
├── pom.xml # Maven build file
17+
└── target/
18+
└── PluginName-1.0.0.jar # Built JAR goes in mods/ folder
19+
```
20+
21+
## manifest.json (CRITICAL)
22+
23+
The manifest MUST use **PascalCase** field names:
24+
25+
```json
26+
{
27+
"Group": "YourGroup",
28+
"Name": "PluginName",
29+
"Version": "1.0.0",
30+
"Main": "com.yourplugin.YourPlugin",
31+
"Description": "Plugin description",
32+
"Authors": [],
33+
"Website": "",
34+
"Dependencies": {},
35+
"OptionalDependencies": {}
36+
}
37+
```
38+
39+
**Important:** Using lowercase field names (e.g., `name` instead of `Name`) will cause validation errors!
40+
41+
## Main Plugin Class
42+
43+
Extend `JavaPlugin` (NOT `PluginBase`) for external plugins:
44+
45+
```java
46+
import com.hypixel.hytale.server.core.plugin.JavaPlugin;
47+
import com.hypixel.hytale.server.core.plugin.JavaPluginInit;
48+
49+
public class YourPlugin extends JavaPlugin {
50+
51+
public YourPlugin(JavaPluginInit init) {
52+
super(init);
53+
}
54+
55+
@Override
56+
public void setup() {
57+
// Register commands, initialize storage
58+
getCommandRegistry().registerCommand(new YourCommand(this));
59+
}
60+
61+
@Override
62+
public void start() {
63+
// Called after setup
64+
}
65+
66+
@Override
67+
public void shutdown() {
68+
// Cleanup, save data
69+
}
70+
}
71+
```
72+
73+
## Commands
74+
75+
Extend `AbstractPlayerCommand` for player-only commands:
76+
77+
```java
78+
import com.hypixel.hytale.server.core.command.system.CommandContext;
79+
import com.hypixel.hytale.server.core.command.system.arguments.system.OptionalArg;
80+
import com.hypixel.hytale.server.core.command.system.arguments.system.RequiredArg;
81+
import com.hypixel.hytale.server.core.command.system.arguments.types.ArgTypes;
82+
import com.hypixel.hytale.server.core.command.system.basecommands.AbstractPlayerCommand;
83+
84+
public class YourCommand extends AbstractPlayerCommand {
85+
86+
private final OptionalArg<String> optionalArg;
87+
private final RequiredArg<String> requiredArg;
88+
89+
public YourCommand(YourPlugin plugin) {
90+
super("commandname", "Command description");
91+
92+
// Optional argument
93+
this.optionalArg = withOptionalArg("argname", "Arg description", ArgTypes.STRING);
94+
95+
// Required argument
96+
this.requiredArg = withRequiredArg("argname", "Arg description", ArgTypes.STRING);
97+
98+
// Require permission
99+
requirePermission("yourplugin.use");
100+
}
101+
102+
@Override
103+
protected void execute(@Nonnull CommandContext ctx,
104+
@Nonnull Store<EntityStore> store,
105+
@Nonnull Ref<EntityStore> playerRef,
106+
@Nonnull PlayerRef playerData,
107+
@Nonnull World world) {
108+
109+
// Get argument values
110+
String optional = optionalArg.get(ctx);
111+
String required = requiredArg.get(ctx);
112+
113+
// Get Player component for permissions
114+
Player player = store.getComponent(playerRef, Player.getComponentType());
115+
116+
// Check permissions
117+
if (player.hasPermission("some.permission")) {
118+
// ...
119+
}
120+
121+
// Send messages
122+
playerData.sendMessage(Message.raw("Hello!").color(new Color(85, 255, 85)));
123+
}
124+
}
125+
```
126+
127+
## Messages & Colors
128+
129+
Hytale uses a fluent API for messages - NOT Minecraft color codes (§):
130+
131+
```java
132+
import com.hypixel.hytale.server.core.Message;
133+
import java.awt.Color;
134+
135+
// Define colors
136+
Color GREEN = new Color(85, 255, 85);
137+
Color RED = new Color(255, 85, 85);
138+
Color YELLOW = new Color(255, 255, 85);
139+
Color GOLD = new Color(255, 170, 0);
140+
Color GRAY = new Color(170, 170, 170);
141+
Color AQUA = new Color(85, 255, 255);
142+
143+
// Send colored message
144+
playerData.sendMessage(Message.raw("Success!").color(GREEN));
145+
146+
// DON'T use Minecraft codes - they show as literal text:
147+
// playerData.sendMessage(Message.raw("§aSuccess!")); // WRONG - shows "§aSuccess!"
148+
```
149+
150+
## Teleportation
151+
152+
Use the Teleport component:
153+
154+
```java
155+
import com.hypixel.hytale.math.vector.Vector3d;
156+
import com.hypixel.hytale.math.vector.Vector3f;
157+
import com.hypixel.hytale.server.core.modules.entity.teleport.Teleport;
158+
159+
// Must execute on world thread
160+
world.execute(() -> {
161+
Vector3d position = new Vector3d(x, y, z);
162+
Vector3f rotation = new Vector3f(yaw, pitch, 0);
163+
164+
Teleport teleport = new Teleport(world, position, rotation);
165+
store.addComponent(playerRef, Teleport.getComponentType(), teleport);
166+
});
167+
```
168+
169+
## Player Position
170+
171+
Get player position via TransformComponent:
172+
173+
```java
174+
import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent;
175+
176+
TransformComponent transform = store.getComponent(playerRef, TransformComponent.getComponentType());
177+
Vector3d position = transform.getPosition();
178+
Vector3f rotation = transform.getRotation();
179+
180+
double x = position.getX();
181+
double y = position.getY();
182+
double z = position.getZ();
183+
float yaw = rotation.getYaw();
184+
float pitch = rotation.getPitch();
185+
```
186+
187+
## Permissions
188+
189+
```java
190+
// Check permission
191+
Player player = store.getComponent(playerRef, Player.getComponentType());
192+
if (player.hasPermission("myplugin.admin")) {
193+
// Has permission
194+
}
195+
196+
// Console commands for permission management:
197+
// perm user add <player> <permission>
198+
// perm group add <group> <permission>
199+
// perm group remove <group> <permission>
200+
```
201+
202+
## Data Storage
203+
204+
Use `getDataDirectory()` for plugin data folder:
205+
206+
```java
207+
Path dataDir = getDataDirectory(); // plugins/YourPlugin/
208+
Path homesDir = dataDir.resolve("homes");
209+
Files.createDirectories(homesDir);
210+
211+
// Use Gson for JSON (provided by Hytale)
212+
Gson gson = new GsonBuilder().setPrettyPrinting().create();
213+
```
214+
215+
## Scheduling / Delayed Tasks
216+
217+
Use Java's ScheduledExecutorService, but execute game actions on world thread:
218+
219+
```java
220+
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
221+
222+
// Schedule task
223+
scheduler.schedule(() -> {
224+
// Run on world thread for game actions
225+
world.execute(() -> {
226+
// Teleport, modify entities, etc.
227+
});
228+
}, 3, TimeUnit.SECONDS);
229+
230+
// Don't forget to shutdown in plugin shutdown()
231+
scheduler.shutdown();
232+
```
233+
234+
## Building
235+
236+
### pom.xml
237+
238+
```xml
239+
<?xml version="1.0" encoding="UTF-8"?>
240+
<project xmlns="http://maven.apache.org/POM/4.0.0"
241+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
242+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
243+
<modelVersion>4.0.0</modelVersion>
244+
245+
<groupId>com.yourplugin</groupId>
246+
<artifactId>YourPlugin</artifactId>
247+
<version>1.0.0</version>
248+
<packaging>jar</packaging>
249+
250+
<properties>
251+
<maven.compiler.source>25</maven.compiler.source>
252+
<maven.compiler.target>25</maven.compiler.target>
253+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
254+
</properties>
255+
256+
<dependencies>
257+
<!-- Hytale Server API -->
258+
<dependency>
259+
<groupId>com.hypixel.hytale</groupId>
260+
<artifactId>HytaleServer</artifactId>
261+
<version>1.0.0</version>
262+
<scope>system</scope>
263+
<systemPath>${project.basedir}/../../HytaleServer.jar</systemPath>
264+
</dependency>
265+
266+
<!-- Gson (provided by Hytale) -->
267+
<dependency>
268+
<groupId>com.google.code.gson</groupId>
269+
<artifactId>gson</artifactId>
270+
<version>2.10.1</version>
271+
<scope>provided</scope>
272+
</dependency>
273+
274+
<!-- Annotations -->
275+
<dependency>
276+
<groupId>com.google.code.findbugs</groupId>
277+
<artifactId>jsr305</artifactId>
278+
<version>3.0.2</version>
279+
<scope>provided</scope>
280+
</dependency>
281+
</dependencies>
282+
283+
<build>
284+
<resources>
285+
<resource>
286+
<directory>src/main/resources</directory>
287+
<filtering>true</filtering>
288+
</resource>
289+
</resources>
290+
<plugins>
291+
<plugin>
292+
<groupId>org.apache.maven.plugins</groupId>
293+
<artifactId>maven-compiler-plugin</artifactId>
294+
<version>3.11.0</version>
295+
</plugin>
296+
<plugin>
297+
<groupId>org.apache.maven.plugins</groupId>
298+
<artifactId>maven-jar-plugin</artifactId>
299+
<version>3.3.0</version>
300+
</plugin>
301+
</plugins>
302+
</build>
303+
</project>
304+
```
305+
306+
### Build Command
307+
308+
```bash
309+
mvn clean package
310+
```
311+
312+
### Installation
313+
314+
1. Copy JAR to `Server/mods/` folder (NOT plugins/)
315+
2. Start server with: `java -jar HytaleServer.jar --assets Assets.zip`
316+
3. Plugin loads automatically on server start
317+
318+
## Server Commands
319+
320+
```bash
321+
# Start server
322+
cd Server
323+
java -jar HytaleServer.jar --assets Assets.zip
324+
325+
# In-game/console commands
326+
plugin list # List loaded plugins
327+
plugin load Group:PluginName # Load a plugin
328+
plugin reload Group:PluginName # Reload a plugin
329+
330+
# Permissions
331+
perm user add <player> <permission>
332+
perm group add <group> <permission>
333+
op add <player> # Make player operator
334+
```
335+
336+
## Common Issues
337+
338+
1. **"Name can't be null" error**: Use PascalCase in manifest.json (`Name` not `name`)
339+
2. **Plugin not loading**: Put JAR in `mods/` folder, not `plugins/`
340+
3. **Color codes showing as text**: Use `Message.raw().color(Color)`, not `§` codes
341+
4. **Teleport not working**: Must run on world thread via `world.execute()`
342+
5. **Class not found**: Ensure you extend `JavaPlugin`, not `PluginBase`
343+
6. **Build fails with Java version**: Hytale requires Java 25
344+
345+
## Useful Imports
346+
347+
```java
348+
// Plugin
349+
import com.hypixel.hytale.server.core.plugin.JavaPlugin;
350+
import com.hypixel.hytale.server.core.plugin.JavaPluginInit;
351+
352+
// Commands
353+
import com.hypixel.hytale.server.core.command.system.CommandContext;
354+
import com.hypixel.hytale.server.core.command.system.basecommands.AbstractPlayerCommand;
355+
import com.hypixel.hytale.server.core.command.system.arguments.system.OptionalArg;
356+
import com.hypixel.hytale.server.core.command.system.arguments.system.RequiredArg;
357+
import com.hypixel.hytale.server.core.command.system.arguments.types.ArgTypes;
358+
359+
// Entity/Player
360+
import com.hypixel.hytale.server.core.entity.entities.Player;
361+
import com.hypixel.hytale.server.core.universe.PlayerRef;
362+
import com.hypixel.hytale.server.core.universe.world.World;
363+
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
364+
import com.hypixel.hytale.component.Ref;
365+
import com.hypixel.hytale.component.Store;
366+
367+
// Transform/Position
368+
import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent;
369+
import com.hypixel.hytale.math.vector.Vector3d;
370+
import com.hypixel.hytale.math.vector.Vector3f;
371+
372+
// Teleport
373+
import com.hypixel.hytale.server.core.modules.entity.teleport.Teleport;
374+
375+
// Messages
376+
import com.hypixel.hytale.server.core.Message;
377+
```

0 commit comments

Comments
 (0)