package gameserver import ( "log" "ananta-ps/pkg/protocol" ) type UrbanCrowdEngine struct { server *Server crowdDensity float32 } func NewUrbanCrowdEngine(srv *Server) *UrbanCrowdEngine { return &UrbanCrowdEngine{ server: srv, crowdDensity: 1.0, } } func (s *Server) handleAskSetCrowdDensity(sess *Session, pkt *protocol.RpcPacket) error { r := protocol.NewUxReader(pkt.Body) density, _ := r.F32() log.Printf("[CROWD] Set crowd density = %.2f", density) if err := sess.ReturnEmptyOk(pkt.InvokeID, pkt.MethodID); err != nil { return err } w := protocol.NewUxWriter() w.F32(density) _ = sess.NotifyData(protocol.MethodGetMethodIDDefault("SyncSetCrowdDensity", 68996045), w.Bytes()) return sess.NotifyData(protocol.MethodGetMethodIDDefault("SyncCrowdSpecifiedDensityRefresh", 68195167), w.Bytes()) } // Dialog RPC Handlers func (s *Server) handleAskStartDialog(sess *Session, pkt *protocol.RpcPacket) error { r := protocol.NewUxReader(pkt.Body) npcId, _ := r.U64() dialogId, _ := r.U32() log.Printf("[DIALOG] AskStartDialog npc=%d dialog=%d", npcId, dialogId) // Return dialog session id wRet := protocol.NewUxWriter() wRet.U32(dialogId) return sess.ReturnData(pkt.InvokeID, pkt.MethodID, wRet.Bytes()) } func (s *Server) handleAskDoDialogAction(sess *Session, pkt *protocol.RpcPacket) error { r := protocol.NewUxReader(pkt.Body) dialogId, _ := r.U32() actionId, _ := r.U32() log.Printf("[DIALOG] AskDoDialogAction dialog=%d action=%d", dialogId, actionId) return sess.ReturnEmptyOk(pkt.InvokeID, pkt.MethodID) } func (s *Server) handleAskForceFinishDialog(sess *Session, pkt *protocol.RpcPacket) error { log.Printf("[DIALOG] AskForceFinishDialog") return sess.ReturnEmptyOk(pkt.InvokeID, pkt.MethodID) } func (s *Server) handleGetCharacterRandomDialog(sess *Session, pkt *protocol.RpcPacket) error { r := protocol.NewUxReader(pkt.Body) charId, _ := r.U32() log.Printf("[DIALOG] GetCharacterRandomDialog for character=%d", charId) wRet := protocol.NewUxWriter() wRet.U32(10001) // Default random dialog ID return sess.ReturnData(pkt.InvokeID, pkt.MethodID, wRet.Bytes()) } func (s *Server) handleAskAgentStartNpcSound(sess *Session, pkt *protocol.RpcPacket) error { r := protocol.NewUxReader(pkt.Body) npcId, _ := r.U64() soundId, _ := r.U32() log.Printf("[NPC] AgentStartNpcSound npc=%d sound=%d", npcId, soundId) return sess.ReturnEmptyOk(pkt.InvokeID, pkt.MethodID) } func (s *Server) handleAskDoNpcAction(sess *Session, pkt *protocol.RpcPacket) error { r := protocol.NewUxReader(pkt.Body) npcId, _ := r.U64() actionName, _ := r.UxString() log.Printf("[NPC] DoNpcAction npc=%d action='%s'", npcId, actionName) return sess.ReturnEmptyOk(pkt.InvokeID, pkt.MethodID) } // Phone & Contacts func (s *Server) handleAskPhoneAddCallRecord(sess *Session, pkt *protocol.RpcPacket) error { r := protocol.NewUxReader(pkt.Body) contactId, _ := r.U32() log.Printf("[PHONE] AddCallRecord contactId=%d", contactId) return sess.ReturnEmptyOk(pkt.InvokeID, pkt.MethodID) } func (s *Server) handleAskPhoneContactOptionAction(sess *Session, pkt *protocol.RpcPacket) error { r := protocol.NewUxReader(pkt.Body) contactId, _ := r.U32() optionId, _ := r.U32() log.Printf("[PHONE] ContactOptionAction contact=%d option=%d", contactId, optionId) return sess.ReturnEmptyOk(pkt.InvokeID, pkt.MethodID) } // Tab-Wheel Companion / Boss Summoning func (s *Server) handleAskSummonGangMember(sess *Session, pkt *protocol.RpcPacket) error { r := protocol.NewUxReader(pkt.Body) charId, _ := r.U32() if charId == 0 { charId = 1002 } companionUnitId := uint64(0x5500000000000000) | uint64(charId) log.Printf("[COMPANION] SummonGangMember charId=%d unitId=%d for player=%d", charId, companionUnitId, sess.pid) if err := sess.ReturnEmptyOk(pkt.InvokeID, pkt.MethodID); err != nil { return err } // Spawn companion in the world proj := protocol.EncodeRaidBattleUnitSpirit(companionUnitId, charId, sess.posX+2.0, sess.posY, sess.posZ+2.0, sess.facing, sess.pid) return sess.NotifyData(protocol.MethodSyncRaidBattleUnitSpirit, proj) } func (s *Server) handleAskDestroyAllGangMember(sess *Session, pkt *protocol.RpcPacket) error { log.Printf("[COMPANION] DestroyAllGangMember for player=%d", sess.pid) return sess.ReturnEmptyOk(pkt.InvokeID, pkt.MethodID) }