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