Corentin Cailleaud commited on
Commit
e14d52f
1 Parent(s): d9c9227
Files changed (1) hide show
  1. cubzh.lua +2 -415
cubzh.lua CHANGED
@@ -1,8 +1,8 @@
1
  math.randomseed(math.floor(Time.UnixMilli() % 100000))
2
 
3
  Modules = {
4
- --gigax = "github.com/GigaxGames/integrations/cubzh:5025b99",
5
- pathfinding = "github.com/caillef/cubzh-library/pathfinding:0119330",
6
  floating_island_generator = "github.com/caillef/cubzh-library/floating_island_generator:82d22a5",
7
  easy_onboarding = "github.com/caillef/cubzh-library/easy_onboarding:77728ee",
8
  }
@@ -11,417 +11,6 @@ Config = {
11
  Items = { "pratamacam.squirrel" },
12
  }
13
 
14
- math.randomseed(math.floor(Time.UnixMilli() % 100000))
15
-
16
- Config = {
17
- Items = { "pratamacam.squirrel" },
18
- }
19
-
20
- local gigax = {}
21
-
22
- local CUBZH_API_TOKEN =
23
- "H4gjL-e9kvLF??2pz6oh=kJL497cBnsyCrQFdVkFadUkLnIaEamroYHb91GywMXrbGeDdmTiHxi8EqmJduCKPrDnfqWsjGuF0JJCUTrasGcBfGx=tlJCjq5q8jhVHWL?krIE74GT9AJ7qqX8nZQgsDa!Unk8GWaqWcVYT-19C!tCo11DcLvrnJPEOPlSbH7dDcXmAMfMEf1ZwZ1v1C9?2/BjPDeiAVTRlLFilwRFmKz7k4H-kCQnDH-RrBk!ZHl7"
24
- local API_URL = "https://gig.ax"
25
-
26
- local TRIGGER_AREA_SIZE = Number3(60, 30, 60)
27
-
28
- local headers = {
29
- ["Content-Type"] = "application/json",
30
- ["Authorization"] = CUBZH_API_TOKEN,
31
- }
32
-
33
- -- HELPERS
34
- local _helpers = {}
35
-
36
- _helpers.lookAt = function(obj, target)
37
- if not target then
38
- require("ease"):linear(obj, 0.1).Forward = obj.initialForward
39
- obj.Tick = nil
40
- return
41
- end
42
- obj.Tick = function(self, _)
43
- _helpers.lookAtHorizontal(self, target)
44
- end
45
- end
46
-
47
- _helpers.lookAtHorizontal = function(o1, o2)
48
- local n3_1 = Number3.Zero
49
- local n3_2 = Number3.Zero
50
- n3_1:Set(o1.Position.X, 0, o1.Position.Z)
51
- n3_2:Set(o2.Position.X, 0, o2.Position.Z)
52
- require("ease"):linear(o1, 0.1).Forward = n3_2 - n3_1
53
- end
54
-
55
- -- Function to calculate distance between two positions
56
- _helpers.calculateDistance = function(_, pos1, pos2)
57
- local dx = pos1.X - pos2.X
58
- local dy = pos1.Y - pos2.Y
59
- local dz = pos1.Z - pos2.Z
60
- return math.sqrt(dx * dx + dy * dy + dz * dz)
61
- end
62
-
63
- _helpers.findClosestLocation = function(_, position, locationData)
64
- if not locationData then
65
- return
66
- end
67
- local closestLocation = nil
68
- local smallestDistance = math.huge -- Large initial value
69
-
70
- for _, location in pairs(locationData) do
71
- local distance = _helpers:calculateDistance(
72
- position,
73
- Map:WorldToBlock(Number3(location.position.x, location.position.y, location.position.z))
74
- )
75
- if distance < smallestDistance then
76
- smallestDistance = distance
77
- closestLocation = location
78
- end
79
- end
80
- -- Closest location found, now send its ID to update the character's location
81
- return closestLocation
82
- end
83
-
84
- if IsClient then
85
- local simulation = {}
86
-
87
- local npcDataClientById = {}
88
- local waitingLinkNPCs = {}
89
- local skillCallbacks = {}
90
-
91
- local gigaxHttpClient = {}
92
- gigaxHttpClient.registerMainCharacter = function(_, engineId, locationId, callback)
93
- local body = JSON:Encode({
94
- name = Player.Username,
95
- physical_description = "A human playing the game",
96
- current_location_id = locationId,
97
- position = { x = 0, y = 0, z = 0 },
98
- })
99
- local apiUrl = API_URL .. "/api/character/company/main?engine_id=" .. engineId
100
- HTTP:Post(apiUrl, headers, body, function(response)
101
- if response.StatusCode ~= 200 then
102
- print("Error creating or fetching main character: " .. response.StatusCode)
103
- return
104
- end
105
- callback(response.Body)
106
- end)
107
- end
108
-
109
- gigaxHttpClient.stepMainCharacter = function(_, engineId, characterId, skill, content, npcName, npcId, callback)
110
- if not engineId then
111
- return
112
- end
113
- local stepUrl = API_URL .. "/api/character/" .. characterId .. "/step-no-ws?engine_id=" .. engineId
114
- local body = JSON:Encode({
115
- character_id = characterId,
116
- skill = skill,
117
- target_name = npcName,
118
- target = npcId,
119
- content = content,
120
- })
121
- HTTP:Post(stepUrl, headers, body, function(response)
122
- if response.StatusCode ~= 200 then
123
- print("Error stepping character: " .. response.StatusCode)
124
- return
125
- end
126
- callback(response.Body)
127
- end)
128
- end
129
-
130
- gigaxHttpClient.updateCharacterPosition = function(_, engineId, characterId, locationId, position, callback)
131
- local body = JSON:Encode({
132
- current_location_id = locationId,
133
- position = { x = position.X, y = position.Y, z = position.Z },
134
- })
135
- local apiUrl = API_URL .. "/api/character/" .. characterId .. "?engine_id=" .. engineId
136
- HTTP:Post(apiUrl, headers, body, function(response)
137
- if response.StatusCode ~= 200 then
138
- print("Error updating character location: " .. response.StatusCode)
139
- return
140
- end
141
- if callback then
142
- callback(response.Body)
143
- end
144
- end)
145
- end
146
-
147
- local onEndData
148
- local prevAction
149
- local function npcResponse(actionData)
150
- local currentAction = string.lower(actionData.skill.name)
151
- if onEndData and skillCallbacks[prevAction].onEndCallback then
152
- skillCallbacks[prevAction].onEndCallback(gigax, onEndData, currentAction)
153
- end
154
- local callback = skillCallbacks[currentAction].callback
155
- prevAction = string.lower(actionData.skill.name)
156
- if not callback then
157
- return
158
- end
159
- onEndData = callback(gigax, actionData, simulation.config)
160
- end
161
-
162
- local function registerEngine(config)
163
- local apiUrl = API_URL .. "/api/engine/company/"
164
-
165
- simulation.locations = {}
166
- simulation.NPCs = {}
167
- simulation.config = config
168
- simulation.player = Player
169
-
170
- -- Prepare the data structure expected by the backend
171
- local engineData = {
172
- name = Player.UserID .. ":" .. config.simulationName,
173
- description = config.simulationDescription,
174
- NPCs = {},
175
- locations = {},
176
- radius,
177
- }
178
-
179
- for _, npc in pairs(config.NPCs) do
180
- simulation.NPCs[npc.name] = {
181
- name = npc.name,
182
- physical_description = npc.physicalDescription,
183
- psychological_profile = npc.psychologicalProfile,
184
- initial_reflections = npc.initialReflections,
185
- current_location_name = npc.currentLocationName,
186
- skills = config.skills,
187
- }
188
- table.insert(engineData.NPCs, simulation.NPCs[npc.name])
189
- end
190
-
191
- for _, loc in ipairs(config.locations) do
192
- simulation.locations[loc.name] = {
193
- name = loc.name,
194
- position = { x = loc.position.X, y = loc.position.Y, z = loc.position.Z },
195
- description = loc.description,
196
- }
197
- table.insert(engineData.locations, simulation.locations[loc.name])
198
- end
199
-
200
- local body = JSON:Encode(engineData)
201
- HTTP:Post(apiUrl, headers, body, function(res)
202
- if res.StatusCode ~= 201 then
203
- print("Error updating engine: " .. res.StatusCode)
204
- return
205
- end
206
- -- Decode the response body to extract engine and location IDs
207
- local responseData = JSON:Decode(res.Body)
208
-
209
- -- Save the engine_id for future use
210
- simulation.engineId = responseData.engine.id
211
-
212
- -- Saving all the _ids inside locationData table:
213
- for _, loc in ipairs(responseData.locations) do
214
- simulation.locations[loc.name]._id = loc._id
215
- end
216
-
217
- -- same for characters:
218
- for _, npc in pairs(responseData.NPCs) do
219
- simulation.NPCs[npc.name]._id = npc._id
220
- simulation.NPCs[npc.name].position = Number3(npc.position.x, npc.position.y, npc.position.z)
221
- end
222
-
223
- gigaxHttpClient:registerMainCharacter(
224
- simulation.engineId,
225
- simulation.locations[config.startingLocationName]._id,
226
- function(body)
227
- simulation.character = JSON:Decode(body)
228
- for name, npc in pairs(waitingLinkNPCs) do
229
- npc._id = simulation.NPCs[name]._id
230
- npc.name = name
231
- npcDataClientById[npc._id] = npc
232
- end
233
- Timer(1, true, function()
234
- local position = Map:WorldToBlock(Player.Position)
235
- gigax:updateCharacterPosition(simulation, simulation.character._id, position)
236
- end)
237
- end
238
- )
239
- end)
240
- end
241
-
242
- findTargetNpc = function(player)
243
- if not simulation or type(simulation.NPCs) ~= "table" then
244
- return
245
- end
246
-
247
- local closerDist = 1000
248
- local closerNpc
249
- for _, npc in pairs(simulation.NPCs) do
250
- local dist = (npc.position - player.Position).Length
251
- if closerDist > dist then
252
- closerDist = dist
253
- closerNpc = npc
254
- end
255
- end
256
- if closerDist > 50 then
257
- return
258
- end -- max distance is 50
259
- return closerNpc
260
- end
261
-
262
- gigax.action = function(_, data)
263
- local npc = findTargetNpc(Player)
264
- if not npc then
265
- return
266
- end
267
-
268
- local content = data.content
269
- data.content = nil
270
- gigaxHttpClient:stepMainCharacter(
271
- simulation.engineId,
272
- simulation.character._id,
273
- data,
274
- content,
275
- npc.name,
276
- npc._id,
277
- function(body)
278
- local actions = JSON:Decode(body)
279
- for _, action in ipairs(actions) do
280
- npcResponse(action)
281
- end
282
- end
283
- )
284
- end
285
-
286
- gigax.getNpc = function(_, id)
287
- return npcDataClientById[id]
288
- end
289
-
290
- local skillOnAction = function(actionType, callback, onEndCallback)
291
- skillCallbacks[actionType] = {
292
- callback = callback,
293
- onEndCallback = onEndCallback,
294
- }
295
- end
296
-
297
- local prevSyncPosition
298
- gigax.updateCharacterPosition = function(_, simulation, characterId, position)
299
- if not simulation then
300
- return
301
- end
302
- if position == prevSyncPosition then
303
- return
304
- end
305
- prevSyncPosition = position
306
- local closest = _helpers:findClosestLocation(position, simulation.locations)
307
- if not closest then
308
- print("can't update character position: no closest location found, id:", characterId, position)
309
- return
310
- end
311
- if not characterId then
312
- return
313
- end
314
- gigaxHttpClient:updateCharacterPosition(simulation.engineId, characterId, closest._id, position)
315
- end
316
-
317
- local function createNPC(name, gameName, currentPosition, rotation)
318
- -- Create the NPC's Object and Avatar
319
- local NPC = {}
320
- NPC.object = Object()
321
- World:AddChild(NPC.object)
322
- NPC.object.Position = currentPosition or Number3(0, 0, 0)
323
- NPC.object.Scale = 0.5
324
- NPC.object.Physics = PhysicsMode.Trigger
325
- NPC.object.CollisionBox = Box({
326
- -TRIGGER_AREA_SIZE.Width * 0.5,
327
- math.min(-TRIGGER_AREA_SIZE.Height, NPC.object.CollisionBox.Min.Y),
328
- -TRIGGER_AREA_SIZE.Depth * 0.5,
329
- }, {
330
- TRIGGER_AREA_SIZE.Width * 0.5,
331
- math.max(TRIGGER_AREA_SIZE.Height, NPC.object.CollisionBox.Max.Y),
332
- TRIGGER_AREA_SIZE.Depth * 0.5,
333
- })
334
-
335
- local text = Text()
336
- text.Text = " " .. gameName .. " "
337
- text:SetParent(NPC.object)
338
- text.Type = TextType.Screen
339
- text.IsUnlit = true
340
- text.LocalPosition.Y = 36
341
- text.FontSize = 22
342
- text.Font = Font.Noto
343
-
344
- NPC.object.OnCollisionBegin = function(self, other)
345
- if other ~= Player then
346
- return
347
- end
348
- _helpers.lookAt(self.avatarContainer, other)
349
- end
350
- NPC.object.OnCollisionEnd = function(self, other)
351
- if other ~= Player then
352
- return
353
- end
354
- _helpers.lookAt(self.avatarContainer, nil)
355
- end
356
-
357
- local container = Object()
358
- container.Rotation:Set(rotation or Number3.Zero)
359
- container.initialForward = container.Forward:Copy()
360
- container:SetParent(NPC.object)
361
- container.Physics = PhysicsMode.Trigger
362
- NPC.object.avatarContainer = container
363
-
364
- NPC.avatar = require("avatar"):get(name)
365
- NPC.avatar:SetParent(NPC.object.avatarContainer)
366
-
367
- NPC.name = name
368
- NPC.gameName = gameName
369
-
370
- NPC.object.onIdle = function()
371
- local animations = NPC.avatar.Animations
372
- NPC.object.avatarContainer.LocalRotation = { 0, 0, 0 }
373
- if not animations or animations.Idle.IsPlaying then
374
- return
375
- end
376
- if animations.Walk.IsPlaying then
377
- animations.Walk:Stop()
378
- end
379
- animations.Idle:Play()
380
- end
381
-
382
- NPC.object.onMove = function()
383
- local animations = NPC.avatar.Animations
384
- NPC.object.avatarContainer.LocalRotation = { 0, 0, 0 }
385
- if not animations or animations.Walk.IsPlaying then
386
- return
387
- end
388
- if animations.Idle.IsPlaying then
389
- animations.Idle:Stop()
390
- end
391
- animations.Walk:Play()
392
- end
393
-
394
- waitingLinkNPCs[name] = NPC
395
-
396
- -- review this to update location and position
397
- Timer(1, true, function()
398
- if not simulation then
399
- return
400
- end
401
- local position = Map:WorldToBlock(NPC.object.Position)
402
- local prevPosition = NPC.object.prevSyncPosition
403
- if prevPosition == position then
404
- return
405
- end
406
- gigax:updateCharacterPosition(simulation, NPC._id, position)
407
- NPC.object.prevSyncPosition = position
408
- end)
409
- return NPC
410
- end
411
-
412
- gigax.setConfig = function(_, config)
413
- for _, elem in ipairs(config.skills) do
414
- skillOnAction(string.lower(elem.name), elem.callback, elem.onEndCallback)
415
- elem.callback = nil
416
- elem.onEndCallback = nil
417
- end
418
- for _, elem in ipairs(config.NPCs) do
419
- createNPC(elem.name, elem.gameName, elem.position, elem.rotation)
420
- end
421
- registerEngine(config)
422
- end
423
- end
424
-
425
  -- Function to spawn a squirrel above the player
426
  function spawnSquirrelAbovePlayer(player)
427
  local squirrel = Shape(Items.pratamacam.squirrel)
@@ -441,8 +30,6 @@ end
441
  local SIMULATION_NAME = "Islands" .. tostring(math.random())
442
  local SIMULATION_DESCRIPTION = "Three floating islands."
443
 
444
- local occupiedPositions = {}
445
-
446
  local skills = {
447
  {
448
  name = "SAY",
 
1
  math.randomseed(math.floor(Time.UnixMilli() % 100000))
2
 
3
  Modules = {
4
+ gigax = "github.com/GigaxGames/integrations/cubzh:9a71b9f",
5
+ pathfinding = "github.com/caillef/cubzh-library/pathfinding:5f9c6bd",
6
  floating_island_generator = "github.com/caillef/cubzh-library/floating_island_generator:82d22a5",
7
  easy_onboarding = "github.com/caillef/cubzh-library/easy_onboarding:77728ee",
8
  }
 
11
  Items = { "pratamacam.squirrel" },
12
  }
13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  -- Function to spawn a squirrel above the player
15
  function spawnSquirrelAbovePlayer(player)
16
  local squirrel = Shape(Items.pratamacam.squirrel)
 
30
  local SIMULATION_NAME = "Islands" .. tostring(math.random())
31
  local SIMULATION_DESCRIPTION = "Three floating islands."
32
 
 
 
33
  local skills = {
34
  {
35
  name = "SAY",