hytopia 0.1.77 → 0.1.79

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/docs/server.entity.despawn.md +1 -1
  2. package/docs/server.entity.md +44 -2
  3. package/docs/server.entity.parent.md +13 -0
  4. package/docs/server.entity.parentnodename.md +13 -0
  5. package/docs/server.entity.spawn.md +19 -3
  6. package/docs/server.entitymanager.getentitychildren.md +55 -0
  7. package/docs/server.entitymanager.md +14 -0
  8. package/docs/server.entityoptions.md +38 -0
  9. package/docs/server.entityoptions.parent.md +13 -0
  10. package/docs/server.entityoptions.parentnodename.md +13 -0
  11. package/docs/server.gameserver.md +2 -2
  12. package/docs/{server.gameserver.modelmanager.md → server.gameserver.modelregistry.md} +3 -3
  13. package/docs/server.md +1 -1
  14. package/docs/{server.modelmanager.getboundingbox.md → server.modelregistry.getboundingbox.md} +2 -2
  15. package/docs/server.modelregistry.getnodenames.md +55 -0
  16. package/docs/server.modelregistry.instance.md +13 -0
  17. package/docs/server.modelregistry.md +139 -0
  18. package/docs/server.modelregistry.modelhasnode.md +71 -0
  19. package/examples/ai-agents/README.md +47 -0
  20. package/examples/ai-agents/assets/map.json +25828 -0
  21. package/examples/ai-agents/assets/ui/index.html +215 -0
  22. package/examples/ai-agents/index.ts +350 -0
  23. package/examples/ai-agents/package.json +16 -0
  24. package/examples/ai-agents/src/BaseAgent.ts +482 -0
  25. package/examples/ai-agents/src/behaviors/FishingBehavior.ts +181 -0
  26. package/examples/ai-agents/src/behaviors/FollowBehavior.ts +171 -0
  27. package/examples/ai-agents/src/behaviors/MiningBehavior.ts +226 -0
  28. package/examples/ai-agents/src/behaviors/PathfindingBehavior.ts +435 -0
  29. package/examples/ai-agents/src/behaviors/SpeakBehavior.ts +50 -0
  30. package/examples/ai-agents/src/behaviors/TradeBehavior.ts +254 -0
  31. package/examples/entity-controller/MyEntityController.ts +1 -1
  32. package/package.json +1 -1
  33. package/server.api.json +324 -21
  34. package/server.d.ts +47 -22
  35. package/server.js +83 -83
  36. package/docs/server.modelmanager.instance.md +0 -13
  37. package/docs/server.modelmanager.md +0 -111
@@ -0,0 +1,254 @@
1
+ import { World } from "hytopia";
2
+ import { BaseAgent, type AgentBehavior } from "../BaseAgent";
3
+
4
+ interface TradeRequest {
5
+ from: BaseAgent;
6
+ to: BaseAgent;
7
+ offerItems: { name: string; quantity: number }[];
8
+ requestItems: { name: string; quantity: number }[];
9
+ timestamp: number;
10
+ }
11
+ /**
12
+ * Simple implementation of trade behavior for Agents.
13
+ * This is a simple example of how behaviours can have state, in this case, a map of active trade requests.
14
+ * It also demonstrates how Behaviors can manage agent state like the inventory.
15
+ */
16
+ export class TradeBehavior implements AgentBehavior {
17
+ private activeRequests: Map<string, TradeRequest> = new Map();
18
+
19
+ onUpdate(agent: BaseAgent, world: World): void {}
20
+
21
+ private generateTradeId(from: BaseAgent, to: BaseAgent): string {
22
+ return `${from.name}_${to.name}_${Date.now()}`;
23
+ }
24
+
25
+ onToolCall(
26
+ agent: BaseAgent,
27
+ world: World,
28
+ toolName: string,
29
+ args: any
30
+ ): string | void {
31
+ if (toolName === "request_trade") {
32
+ const { target, offer, request } = args;
33
+
34
+ // Find target agent
35
+ const nearbyEntities = agent.getNearbyEntities(5);
36
+ const targetEntity = nearbyEntities.find((e) => e.name === target);
37
+
38
+ if (!targetEntity || targetEntity.type !== "Agent") {
39
+ return `Cannot find ${target} nearby to trade with.`;
40
+ }
41
+
42
+ const targetAgent = world.entityManager
43
+ .getAllEntities()
44
+ .find(
45
+ (e) => e instanceof BaseAgent && e.name === target
46
+ ) as BaseAgent;
47
+
48
+ if (!targetAgent) return "Target agent not found";
49
+
50
+ // Verify agent has the items they're offering
51
+ for (const item of offer) {
52
+ if (!agent.removeFromInventory(item.name, item.quantity)) {
53
+ return `You don't have enough ${item.name} to offer.`;
54
+ }
55
+ // Return items since this is just a check
56
+ agent.addToInventory({
57
+ name: item.name,
58
+ quantity: item.quantity,
59
+ });
60
+ }
61
+
62
+ const tradeId = this.generateTradeId(agent, targetAgent);
63
+ const tradeRequest = {
64
+ from: agent,
65
+ to: targetAgent,
66
+ offerItems: offer,
67
+ requestItems: request,
68
+ timestamp: Date.now(),
69
+ };
70
+
71
+ // Set trade request in both agents' trade behaviors
72
+ this.activeRequests.set(tradeId, tradeRequest);
73
+ const targetTradeBehavior = targetAgent
74
+ .getBehaviors()
75
+ .find((b) => b instanceof TradeBehavior) as TradeBehavior;
76
+ if (targetTradeBehavior) {
77
+ targetTradeBehavior.activeRequests.set(tradeId, tradeRequest);
78
+ }
79
+
80
+ targetAgent.handleEnvironmentTrigger(
81
+ `${agent.name} wants to trade!\n` +
82
+ `Offering: ${offer
83
+ .map(
84
+ (i: { quantity: number; name: string }) =>
85
+ `${i.quantity}x ${i.name}`
86
+ )
87
+ .join(", ")}\n` +
88
+ `Requesting: ${request
89
+ .map(
90
+ (i: { quantity: number; name: string }) =>
91
+ `${i.quantity}x ${i.name}`
92
+ )
93
+ .join(", ")}\n` +
94
+ `Use accept_trade or decline_trade with tradeId: ${tradeId}`
95
+ );
96
+
97
+ return "Trade request sent!";
98
+ } else if (toolName === "accept_trade") {
99
+ const { tradeId } = args;
100
+ const request = this.activeRequests.get(tradeId);
101
+ console.log(`${agent.name} attempting to accept trade ${tradeId}`);
102
+
103
+ if (!request) {
104
+ console.log(`Trade ${tradeId} not found or expired`);
105
+ return "Trade request not found or expired.";
106
+ }
107
+
108
+ if (request.to !== agent) {
109
+ console.log(
110
+ `${agent.name} tried to accept trade meant for ${request.to.name}`
111
+ );
112
+ return "This trade request was not sent to you.";
113
+ }
114
+
115
+ // Verify receiving agent has requested items
116
+ for (const item of request.requestItems) {
117
+ if (!agent.removeFromInventory(item.name, item.quantity)) {
118
+ console.log(
119
+ `${agent.name} lacks required item: ${item.quantity}x ${item.name}`
120
+ );
121
+ return `You don't have enough ${item.name} to complete the trade.`;
122
+ }
123
+
124
+ // Return items since this is just a check
125
+ agent.addToInventory({
126
+ name: item.name,
127
+ quantity: item.quantity,
128
+ });
129
+ }
130
+
131
+ console.log(
132
+ `Executing trade between ${request.from.name} and ${request.to.name}`
133
+ );
134
+ console.log(
135
+ `${request.from.name} offers: ${JSON.stringify(
136
+ request.offerItems
137
+ )}`
138
+ );
139
+ console.log(
140
+ `${request.to.name} offers: ${JSON.stringify(
141
+ request.requestItems
142
+ )}`
143
+ );
144
+
145
+ // Execute the trade
146
+ // Remove items from both agents
147
+ for (const item of request.offerItems) {
148
+ request.from.removeFromInventory(item.name, item.quantity);
149
+ }
150
+ for (const item of request.requestItems) {
151
+ request.to.removeFromInventory(item.name, item.quantity);
152
+ }
153
+
154
+ // Add items to both agents
155
+ for (const item of request.offerItems) {
156
+ request.to.addToInventory({
157
+ name: item.name,
158
+ quantity: item.quantity,
159
+ });
160
+ }
161
+ for (const item of request.requestItems) {
162
+ request.from.addToInventory({
163
+ name: item.name,
164
+ quantity: item.quantity,
165
+ });
166
+ }
167
+
168
+ // Clear trade request from both agents' trade behaviors
169
+ this.activeRequests.delete(tradeId);
170
+ const fromTradeBehavior = request.from
171
+ .getBehaviors()
172
+ .find((b) => b instanceof TradeBehavior) as TradeBehavior;
173
+ if (fromTradeBehavior) {
174
+ fromTradeBehavior.activeRequests.delete(tradeId);
175
+ }
176
+
177
+ console.log(`Trade ${tradeId} completed successfully`);
178
+
179
+ // Notify both agents
180
+ request.from.handleEnvironmentTrigger(
181
+ `${agent.name} accepted your trade!`
182
+ );
183
+ request.to.handleEnvironmentTrigger(
184
+ `You accepted the trade with ${agent.name}!`
185
+ );
186
+ return "Trade completed successfully!";
187
+ } else if (toolName === "decline_trade") {
188
+ const { tradeId } = args;
189
+ const request = this.activeRequests.get(tradeId);
190
+
191
+ if (!request) {
192
+ console.log("Trade request not found or expired.");
193
+ return "Trade request not found or expired.";
194
+ }
195
+
196
+ if (request.to !== agent) {
197
+ console.log("This trade request was not sent to you.");
198
+ return "This trade request was not sent to you.";
199
+ }
200
+
201
+ // Clear trade request from both agents' trade behaviors
202
+ this.activeRequests.delete(tradeId);
203
+ const fromTradeBehavior = request.from
204
+ .getBehaviors()
205
+ .find((b) => b instanceof TradeBehavior) as TradeBehavior;
206
+ if (fromTradeBehavior) {
207
+ fromTradeBehavior.activeRequests.delete(tradeId);
208
+ }
209
+
210
+ request.from.handleEnvironmentTrigger(
211
+ `${agent.name} declined your trade.`
212
+ );
213
+ console.log("Trade declined.");
214
+ return "Trade declined.";
215
+ }
216
+ }
217
+
218
+ getPromptInstructions(): string {
219
+ return `
220
+ To request a trade with another agent:
221
+ <action type="request_trade">
222
+ {
223
+ "target": "name of agent to trade with",
224
+ "offer": [{ "name": "item name", "quantity": number }],
225
+ "request": [{ "name": "item name", "quantity": number }]
226
+ }
227
+ </action>
228
+
229
+ To accept a trade request:
230
+ <action type="accept_trade">
231
+ {
232
+ "tradeId": "trade_id_from_request"
233
+ }
234
+ </action>
235
+
236
+ To decline a trade request:
237
+ <action type="decline_trade">
238
+ {
239
+ "tradeId": "trade_id_from_request"
240
+ }
241
+ </action>
242
+
243
+ Trading requires both agents to be within 5 meters of each other.
244
+ Both agents must have the required items in their inventory.
245
+
246
+ If someone verbally offers a trade, but you don't get the official request from the Environment, you should ask them to request the trade so you can accept it.
247
+
248
+ If you request to trade with an agent, they will need to accept the trade request.`;
249
+ }
250
+
251
+ getState(): string {
252
+ return `Active trade requests: ${JSON.stringify(this.activeRequests)}`;
253
+ }
254
+ }
@@ -144,7 +144,7 @@ export default class MyEntityController extends BaseEntityController {
144
144
  collidesWith: [ CollisionGroup.BLOCK, CollisionGroup.ENTITY ],
145
145
  },
146
146
  isSensor: true,
147
- relativePosition: { x: 0, y: -0.75, z: 0 },
147
+ position: { x: 0, y: -0.75, z: 0 },
148
148
  tag: 'groundSensor',
149
149
  onCollision: (_other: BlockType | Entity, started: boolean) => {
150
150
  // Ground contact
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hytopia",
3
- "version": "0.1.77",
3
+ "version": "0.1.79",
4
4
  "description": "The HYTOPIA SDK makes it easy for developers to create massively multiplayer games using JavaScript or TypeScript.",
5
5
  "main": "server.js",
6
6
  "bin": {