aduermael commited on
Commit
e7a8b8a
1 Parent(s): df5dece

remove timer

Browse files
Files changed (1) hide show
  1. cubzh.lua +421 -4
cubzh.lua CHANGED
@@ -1,5 +1,5 @@
1
  Modules = {
2
- gigax = "github.com/GigaxGames/integrations/cubzh:5025b99",
3
  pathfinding = "github.com/caillef/cubzh-library/pathfinding:f8c4315",
4
  floating_island_generator = "github.com/caillef/cubzh-library/floating_island_generator:82d22a5",
5
  }
@@ -329,6 +329,8 @@ Client.OnWorldObjectLoad = function(obj)
329
  end
330
 
331
  Client.OnStart = function()
 
 
332
  require("object_skills").addStepClimbing(Player, {
333
  mapScale = MAP_SCALE,
334
  collisionGroups = Map.CollisionGroups,
@@ -363,9 +365,7 @@ Client.OnStart = function()
363
 
364
  pathfinding:createPathfindingMap()
365
 
366
- Timer(2, function()
367
- gigax:setConfig(gigaxWorldConfig)
368
- end)
369
 
370
  Player.Avatar:load({ usernameOrId = "aduermael" })
371
  end
@@ -409,3 +409,420 @@ Client.OnChat = function(payload)
409
  print(payload.message)
410
  return true
411
  end
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  Modules = {
2
+ -- gigax = "github.com/GigaxGames/integrations/cubzh:5025b99",
3
  pathfinding = "github.com/caillef/cubzh-library/pathfinding:f8c4315",
4
  floating_island_generator = "github.com/caillef/cubzh-library/floating_island_generator:82d22a5",
5
  }
 
329
  end
330
 
331
  Client.OnStart = function()
332
+ gigax = requireGigax()
333
+
334
  require("object_skills").addStepClimbing(Player, {
335
  mapScale = MAP_SCALE,
336
  collisionGroups = Map.CollisionGroups,
 
365
 
366
  pathfinding:createPathfindingMap()
367
 
368
+ gigax:setConfig(gigaxWorldConfig)
 
 
369
 
370
  Player.Avatar:load({ usernameOrId = "aduermael" })
371
  end
 
409
  print(payload.message)
410
  return true
411
  end
412
+
413
+ function requireGigax()
414
+ local gigax = {}
415
+
416
+ local CUBZH_API_TOKEN =
417
+ "H4gjL-e9kvLF??2pz6oh=kJL497cBnsyCrQFdVkFadUkLnIaEamroYHb91GywMXrbGeDdmTiHxi8EqmJduCKPrDnfqWsjGuF0JJCUTrasGcBfGx=tlJCjq5q8jhVHWL?krIE74GT9AJ7qqX8nZQgsDa!Unk8GWaqWcVYT-19C!tCo11DcLvrnJPEOPlSbH7dDcXmAMfMEf1ZwZ1v1C9?2/BjPDeiAVTRlLFilwRFmKz7k4H-kCQnDH-RrBk!ZHl7"
418
+ local API_URL = "https://gig.ax"
419
+
420
+ local TRIGGER_AREA_SIZE = Number3(60, 30, 60)
421
+
422
+ local headers = {
423
+ ["Content-Type"] = "application/json",
424
+ ["Authorization"] = CUBZH_API_TOKEN,
425
+ }
426
+
427
+ -- HELPERS
428
+ local _helpers = {}
429
+
430
+ _helpers.lookAt = function(obj, target)
431
+ if not target then
432
+ require("ease"):linear(obj, 0.1).Forward = obj.initialForward
433
+ obj.Tick = nil
434
+ return
435
+ end
436
+ obj.Tick = function(self, _)
437
+ _helpers.lookAtHorizontal(self, target)
438
+ end
439
+ end
440
+
441
+ _helpers.lookAtHorizontal = function(o1, o2)
442
+ local n3_1 = Number3.Zero
443
+ local n3_2 = Number3.Zero
444
+ n3_1:Set(o1.Position.X, 0, o1.Position.Z)
445
+ n3_2:Set(o2.Position.X, 0, o2.Position.Z)
446
+ require("ease"):linear(o1, 0.1).Forward = n3_2 - n3_1
447
+ end
448
+
449
+ -- Function to calculate distance between two positions
450
+ _helpers.calculateDistance = function(_, pos1, pos2)
451
+ local dx = pos1.X - pos2.X
452
+ local dy = pos1.Y - pos2.Y
453
+ local dz = pos1.Z - pos2.Z
454
+ return math.sqrt(dx * dx + dy * dy + dz * dz)
455
+ end
456
+
457
+ _helpers.findClosestLocation = function(_, position, locationData)
458
+ if not locationData then
459
+ return
460
+ end
461
+ local closestLocation = nil
462
+ local smallestDistance = math.huge -- Large initial value
463
+
464
+ for _, location in pairs(locationData) do
465
+ local distance = _helpers:calculateDistance(
466
+ position,
467
+ -- Map:WorldToBlock(Number3(location.position.x, location.position.y, location.position.z))
468
+ Number3(location.position.x, location.position.y, location.position.z)
469
+ )
470
+ if distance < smallestDistance then
471
+ smallestDistance = distance
472
+ closestLocation = location
473
+ end
474
+ end
475
+ -- Closest location found, now send its ID to update the character's location
476
+ return closestLocation
477
+ end
478
+
479
+ if IsClient then
480
+ local simulation = {}
481
+
482
+ local npcDataClientById = {}
483
+ local waitingLinkNPCs = {}
484
+ local skillCallbacks = {}
485
+
486
+ local gigaxHttpClient = {}
487
+ gigaxHttpClient.registerMainCharacter = function(_, engineId, locationId, callback)
488
+ local body = JSON:Encode({
489
+ name = Player.Username,
490
+ physical_description = "A human playing the game",
491
+ current_location_id = locationId,
492
+ position = { x = 0, y = 0, z = 0 },
493
+ })
494
+ local apiUrl = API_URL .. "/api/character/company/main?engine_id=" .. engineId
495
+ HTTP:Post(apiUrl, headers, body, function(response)
496
+ if response.StatusCode ~= 200 then
497
+ print("Error creating or fetching main character: " .. response.StatusCode)
498
+ return
499
+ end
500
+ callback(response.Body)
501
+ end)
502
+ end
503
+
504
+ gigaxHttpClient.stepMainCharacter = function(_, engineId, characterId, skill, content, npcName, npcId, callback)
505
+ if not engineId then
506
+ return
507
+ end
508
+ local stepUrl = API_URL .. "/api/character/" .. characterId .. "/step-no-ws?engine_id=" .. engineId
509
+ local body = JSON:Encode({
510
+ character_id = characterId,
511
+ skill = skill,
512
+ target_name = npcName,
513
+ target = npcId,
514
+ content = content,
515
+ })
516
+ HTTP:Post(stepUrl, headers, body, function(response)
517
+ if response.StatusCode ~= 200 then
518
+ print("Error stepping character: " .. response.StatusCode)
519
+ return
520
+ end
521
+ callback(response.Body)
522
+ end)
523
+ end
524
+
525
+ gigaxHttpClient.updateCharacterPosition = function(_, engineId, characterId, locationId, position, callback)
526
+ local body = JSON:Encode({
527
+ current_location_id = locationId,
528
+ position = { x = position.X, y = position.Y, z = position.Z },
529
+ })
530
+ local apiUrl = API_URL .. "/api/character/" .. characterId .. "?engine_id=" .. engineId
531
+ HTTP:Post(apiUrl, headers, body, function(response)
532
+ if response.StatusCode ~= 200 then
533
+ print("Error updating character location: " .. response.StatusCode)
534
+ return
535
+ end
536
+ if callback then
537
+ callback(response.Body)
538
+ end
539
+ end)
540
+ end
541
+
542
+ local onEndData
543
+ local prevAction
544
+ local function npcResponse(actionData)
545
+ local currentAction = string.lower(actionData.skill.name)
546
+ if onEndData and skillCallbacks[prevAction].onEndCallback then
547
+ skillCallbacks[prevAction].onEndCallback(gigax, onEndData, currentAction)
548
+ end
549
+ local callback = skillCallbacks[currentAction].callback
550
+ prevAction = string.lower(actionData.skill.name)
551
+ if not callback then
552
+ return
553
+ end
554
+ onEndData = callback(gigax, actionData, simulation.config)
555
+ end
556
+
557
+ local function registerEngine(config)
558
+ local apiUrl = API_URL .. "/api/engine/company/"
559
+
560
+ simulation.locations = {}
561
+ simulation.NPCs = {}
562
+ simulation.config = config
563
+ simulation.player = Player
564
+
565
+ -- Prepare the data structure expected by the backend
566
+ local engineData = {
567
+ name = Player.UserID .. ":" .. config.simulationName,
568
+ description = config.simulationDescription,
569
+ NPCs = {},
570
+ locations = {},
571
+ radius,
572
+ }
573
+
574
+ for _, npc in pairs(config.NPCs) do
575
+ simulation.NPCs[npc.name] = {
576
+ name = npc.name,
577
+ physical_description = npc.physicalDescription,
578
+ psychological_profile = npc.psychologicalProfile,
579
+ initial_reflections = npc.initialReflections,
580
+ current_location_name = npc.currentLocationName,
581
+ -- skills = config.skills,
582
+ }
583
+ print("simulation.NPCs[" .. npc.name .. "]:", JSON:Encode(simulation.NPCs[npc.name]))
584
+ simulation.NPCs[npc.name].skills = config.skills
585
+
586
+ table.insert(engineData.NPCs, simulation.NPCs[npc.name])
587
+ end
588
+
589
+ for _, loc in ipairs(config.locations) do
590
+ simulation.locations[loc.name] = {
591
+ name = loc.name,
592
+ position = { x = loc.position.X, y = loc.position.Y, z = loc.position.Z },
593
+ description = loc.description,
594
+ }
595
+
596
+ print("simulation.locations[" .. loc.name .. "]:", JSON:Encode(simulation.locations[loc.name]))
597
+
598
+ table.insert(engineData.locations, simulation.locations[loc.name])
599
+ end
600
+
601
+ local body = JSON:Encode(engineData)
602
+ HTTP:Post(apiUrl, headers, body, function(res)
603
+ if res.StatusCode ~= 201 then
604
+ print("Error updating engine: " .. res.StatusCode)
605
+ return
606
+ end
607
+ -- Decode the response body to extract engine and location IDs
608
+ local responseData = JSON:Decode(res.Body)
609
+
610
+ -- Save the engine_id for future use
611
+ simulation.engineId = responseData.engine.id
612
+
613
+ -- Saving all the _ids inside locationData table:
614
+ for _, loc in ipairs(responseData.locations) do
615
+ simulation.locations[loc.name]._id = loc._id
616
+ end
617
+
618
+ -- same for characters:
619
+ for _, npc in pairs(responseData.NPCs) do
620
+ simulation.NPCs[npc.name]._id = npc._id
621
+ print("npc.position:", JSON:Encode(npc.position), npc.name)
622
+ simulation.NPCs[npc.name].position = Number3(npc.position.x, npc.position.y, npc.position.z)
623
+ end
624
+
625
+ gigaxHttpClient:registerMainCharacter(
626
+ simulation.engineId,
627
+ simulation.locations[config.startingLocationName]._id,
628
+ function(body)
629
+ simulation.character = JSON:Decode(body)
630
+ for name, npc in pairs(waitingLinkNPCs) do
631
+ npc._id = simulation.NPCs[name]._id
632
+ npc.name = name
633
+ npcDataClientById[npc._id] = npc
634
+ end
635
+ Timer(1, true, function()
636
+ -- local position = Map:WorldToBlock(Player.Position)
637
+ local position = Player.Position:Copy()
638
+ gigax:updateCharacterPosition(simulation, simulation.character._id, position)
639
+ end)
640
+ end
641
+ )
642
+ end)
643
+ end
644
+
645
+ findTargetNpc = function(player)
646
+ print("findTargetNpc")
647
+ if not simulation then
648
+ return
649
+ end
650
+
651
+ local closerDist = 1000
652
+ local closerNpc
653
+ for _, npc in pairs(simulation.NPCs) do
654
+ print("npc.name:", npc.name, npc.position)
655
+ local dist = (npc.position - player.Position).Length
656
+ if closerDist > dist then
657
+ closerDist = dist
658
+ closerNpc = npc
659
+ end
660
+ end
661
+ if closerDist > 50 then
662
+ return
663
+ end -- max distance is 50
664
+ return closerNpc
665
+ end
666
+
667
+ gigax.action = function(_, data)
668
+ print("data:", JSON:Encode(data))
669
+ local npc = findTargetNpc(Player)
670
+ if not npc then
671
+ print("no NPC")
672
+ return
673
+ end
674
+
675
+ print("npc.name:", npc.name)
676
+ print("simulation.character._id:", simulation.character._id)
677
+
678
+ local content = data.content
679
+ data.content = nil
680
+ gigaxHttpClient:stepMainCharacter(
681
+ simulation.engineId,
682
+ simulation.character._id,
683
+ data,
684
+ content,
685
+ npc.name,
686
+ npc._id,
687
+ function(body)
688
+ print("body:", body:ToString())
689
+ local actions = JSON:Decode(body)
690
+ for _, action in ipairs(actions) do
691
+ npcResponse(action)
692
+ end
693
+ end
694
+ )
695
+ end
696
+
697
+ gigax.getNpc = function(_, id)
698
+ return npcDataClientById[id]
699
+ end
700
+
701
+ local skillOnAction = function(actionType, callback, onEndCallback)
702
+ skillCallbacks[actionType] = {
703
+ callback = callback,
704
+ onEndCallback = onEndCallback,
705
+ }
706
+ end
707
+
708
+ local prevSyncPosition
709
+ gigax.updateCharacterPosition = function(_, simulation, characterId, position)
710
+ if not simulation then
711
+ return
712
+ end
713
+ if position == prevSyncPosition then
714
+ return
715
+ end
716
+ prevSyncPosition = position
717
+ local closest = _helpers:findClosestLocation(position, simulation.locations)
718
+ if not closest then
719
+ print("can't update character position: no closest location found, id:", characterId, position)
720
+ return
721
+ end
722
+ if not characterId then
723
+ return
724
+ end
725
+ print("characterId:", characterId, "closest.name:", closest.name, "position:", position)
726
+ gigaxHttpClient:updateCharacterPosition(simulation.engineId, characterId, closest._id, position)
727
+ end
728
+
729
+ local function createNPC(name, currentPosition, rotation)
730
+ -- Create the NPC's Object and Avatar
731
+ local NPC = {}
732
+ NPC.object = Object()
733
+ World:AddChild(NPC.object)
734
+ NPC.object.Position = currentPosition or Number3(0, 0, 0)
735
+ NPC.object.Scale = 0.5
736
+ NPC.object.Physics = PhysicsMode.Trigger
737
+ NPC.object.CollisionBox = Box({
738
+ -TRIGGER_AREA_SIZE.Width * 0.5,
739
+ math.min(-TRIGGER_AREA_SIZE.Height, NPC.object.CollisionBox.Min.Y),
740
+ -TRIGGER_AREA_SIZE.Depth * 0.5,
741
+ }, {
742
+ TRIGGER_AREA_SIZE.Width * 0.5,
743
+ math.max(TRIGGER_AREA_SIZE.Height, NPC.object.CollisionBox.Max.Y),
744
+ TRIGGER_AREA_SIZE.Depth * 0.5,
745
+ })
746
+ NPC.object.OnCollisionBegin = function(self, other)
747
+ if other ~= Player then
748
+ return
749
+ end
750
+ _helpers.lookAt(self.avatarContainer, other)
751
+ end
752
+ NPC.object.OnCollisionEnd = function(self, other)
753
+ if other ~= Player then
754
+ return
755
+ end
756
+ _helpers.lookAt(self.avatarContainer, nil)
757
+ end
758
+
759
+ local container = Object()
760
+ container.Rotation:Set(rotation or Number3.Zero)
761
+ container.initialForward = container.Forward:Copy()
762
+ container:SetParent(NPC.object)
763
+ container.Physics = PhysicsMode.Trigger
764
+ NPC.object.avatarContainer = container
765
+
766
+ NPC.avatar = require("avatar"):get(name)
767
+ NPC.avatar:SetParent(NPC.object.avatarContainer)
768
+
769
+ NPC.name = name
770
+
771
+ NPC.object.onIdle = function()
772
+ local animations = NPC.avatar.Animations
773
+ NPC.object.avatarContainer.LocalRotation = { 0, 0, 0 }
774
+ if not animations or animations.Idle.IsPlaying then
775
+ return
776
+ end
777
+ if animations.Walk.IsPlaying then
778
+ animations.Walk:Stop()
779
+ end
780
+ animations.Idle:Play()
781
+ end
782
+
783
+ NPC.object.onMove = function()
784
+ local animations = NPC.avatar.Animations
785
+ NPC.object.avatarContainer.LocalRotation = { 0, 0, 0 }
786
+ if not animations or animations.Walk.IsPlaying then
787
+ return
788
+ end
789
+ if animations.Idle.IsPlaying then
790
+ animations.Idle:Stop()
791
+ end
792
+ animations.Walk:Play()
793
+ end
794
+
795
+ waitingLinkNPCs[name] = NPC
796
+
797
+ -- review this to update location and position
798
+ Timer(1, true, function()
799
+ if not simulation then
800
+ return
801
+ end
802
+ -- local position = Map:WorldToBlock(NPC.object.Position)
803
+ local position = NPC.object.Position:Copy()
804
+ local prevPosition = NPC.object.prevSyncPosition
805
+ if prevPosition == position then
806
+ return
807
+ end
808
+ gigax:updateCharacterPosition(simulation, NPC._id, position)
809
+ NPC.object.prevSyncPosition = position
810
+ end)
811
+ return NPC
812
+ end
813
+
814
+ gigax.setConfig = function(_, config)
815
+ for _, elem in ipairs(config.skills) do
816
+ skillOnAction(string.lower(elem.name), elem.callback, elem.onEndCallback)
817
+ elem.callback = nil
818
+ elem.onEndCallback = nil
819
+ end
820
+ for _, elem in ipairs(config.NPCs) do
821
+ createNPC(elem.name, elem.position, elem.rotation)
822
+ end
823
+ registerEngine(config)
824
+ end
825
+ end
826
+
827
+ return gigax
828
+ end