예제 #1
0
        public static Vector3 ToGlobal(this Position p)
        {
            var landblock = LScape.get_landblock(p.LandblockId.Raw);

            if (landblock.IsDungeon)
            {
                return(p.Pos);
            }

            var x = p.LandblockId.LandblockX * Position.BlockLength + p.PositionX;
            var y = p.LandblockId.LandblockY * Position.BlockLength + p.PositionY;
            var z = p.PositionZ;

            return(new Vector3(x, y, z));
        }
예제 #2
0
        /// <summary>
        /// Spawns the semi-randomized monsters scattered around the outdoors<para />
        /// This will be called from a separate task from our constructor. Use thread safety when interacting with this landblock.
        /// </summary>
        private void SpawnEncounters()
        {
            // get the encounter spawns for this landblock
            var encounters = DatabaseManager.World.GetCachedEncountersByLandblock(Id.Landblock);

            foreach (var encounter in encounters)
            {
                var wo = WorldObjectFactory.CreateNewWorldObject(encounter.WeenieClassId);

                if (wo == null)
                {
                    continue;
                }

                var xPos = Math.Clamp(encounter.CellX * 24.0f, 0.5f, 191.5f);
                var yPos = Math.Clamp(encounter.CellY * 24.0f, 0.5f, 191.5f);

                var pos = new Physics.Common.Position();
                pos.ObjCellID = (uint)(Id.Landblock << 16) | 1;
                pos.Frame     = new Physics.Animation.AFrame(new Vector3(xPos, yPos, 0), Quaternion.Identity);
                pos.adjust_to_outside();

                pos.Frame.Origin.Z = _landblock.GetZ(pos.Frame.Origin);

                wo.Location = new Position(pos.ObjCellID, pos.Frame.Origin, pos.Frame.Orientation);

                var sortCell = LScape.get_landcell(pos.ObjCellID) as SortCell;
                if (sortCell != null && sortCell.has_building())
                {
                    continue;
                }

                if (PropertyManager.GetBool("override_encounter_spawn_rates").Item)
                {
                    wo.RegenerationInterval = PropertyManager.GetDouble("encounter_regen_interval").Item;

                    foreach (var profile in wo.Biota.BiotaPropertiesGenerator)
                    {
                        profile.Delay = (float)PropertyManager.GetDouble("encounter_delay").Item;
                    }
                }

                actionQueue.EnqueueAction(new ActionEventDelegate(() =>
                {
                    AddWorldObject(wo);
                }));
            }
        }
예제 #3
0
        /// <summary>
        /// Handles the cleanup process for a landblock
        /// This method is called by LandblockManager
        /// </summary>
        public void Unload()
        {
            var landblockID = Id.Raw | 0xFFFF;

            log.Debug($"Landblock.Unload({landblockID:X})");

            SaveDB();

            // remove all objects
            foreach (var wo in worldObjects.Keys.ToList())
            {
                RemoveWorldObjectInternal(wo);
            }

            // remove physics landblock
            LScape.unload_landblock(landblockID);
        }
예제 #4
0
        public static Vector3 ToGlobal(this Position p)
        {
            var landblock = LScape.get_landblock(p.LandblockId.Raw);

            // TODO: investigate dungeons that are below actual traversable overworld terrain
            // ex., 010AFFFF
            //if (landblock.IsDungeon)
            if (p.Indoors)
            {
                return(p.Pos);
            }

            var x = p.LandblockId.LandblockX * Position.BlockLength + p.PositionX;
            var y = p.LandblockId.LandblockY * Position.BlockLength + p.PositionY;
            var z = p.PositionZ;

            return(new Vector3(x, y, z));
        }
예제 #5
0
        /// <summary>
        /// Returns TRUE if outdoor position is located on walkable slope
        /// </summary>
        public static bool IsWalkable(this Position p)
        {
            if (p.Indoors)
            {
                return(true);
            }

            var landcell = (LandCell)LScape.get_landcell(p.Cell);

            Physics.Polygon walkable    = null;
            var             terrainPoly = landcell.find_terrain_poly(p.Pos, ref walkable);

            if (walkable == null)
            {
                return(false);
            }

            return(Physics.PhysicsObj.is_valid_walkable(walkable.Plane.Normal));
        }
예제 #6
0
        public void UpdatePosition_PhysicsInner(Vector3 newPos, Vector3 dir)
        {
            Location.Rotate(dir);
            PhysicsObj.Position.Frame.Orientation = Location.Rotation;

            var cell = LScape.get_landcell(Location.Cell);

            PhysicsObj.set_request_pos(newPos, Location.Rotation, cell);

            // simulate running forward for this amount of time
            PhysicsObj.update_object_server(false);

            // was the position successfully moved to?
            // use the physics position as the source-of-truth?
            Location.Pos = PhysicsObj.Position.Frame.Origin;
            if (PhysicsObj.CurCell != null && PhysicsObj.CurCell.ID != Location.Cell)
            {
                Location.LandblockId = new LandblockId(PhysicsObj.CurCell.ID);
            }
        }
예제 #7
0
        public Landblock(LandblockId id)
        {
            Id = id;

            CellLandblock = DatManager.CellDat.ReadFromDat <CellLandblock>(Id.Raw >> 16 | 0xFFFF);
            LandblockInfo = DatManager.CellDat.ReadFromDat <LandblockInfo>((uint)Id.Landblock << 16 | 0xFFFE);

            lastActiveTime = DateTime.UtcNow;

            Task.Run(() =>
            {
                _landblock = LScape.get_landblock(Id.Raw);

                CreateWorldObjects();

                SpawnDynamicShardObjects();

                SpawnEncounters();
            });

            //LoadMeshes(objects);
        }
예제 #8
0
        public static void AdjustMapCoords(this Position pos)
        {
            // adjust Z to terrain height
            pos.PositionZ = pos.GetTerrainZ();

            // adjust to building height, if applicable
            var sortCell = LScape.get_landcell(pos.Cell) as SortCell;

            if (sortCell != null && sortCell.has_building())
            {
                var building = sortCell.Building;

                var minZ = building.GetMinZ();

                if (minZ > 0 && minZ < float.MaxValue)
                {
                    pos.PositionZ += minZ;
                }

                pos.LandblockId = new LandblockId(pos.GetCell());
            }
        }
예제 #9
0
        public void BuildEnvCells()
        {
            EnvCells = new List <R_EnvCell>();

            if (Landblock.Info == null || Landblock.Info.NumCells == 0)
            {
                return;
            }

            var numCells = Landblock.Info.NumCells;

            var landblockID = Landblock.ID & 0xFFFF0000;

            for (uint i = 0; i < numCells; i++)
            {
                var envCellID = landblockID | (0x100 + i);

                var envCell = (EnvCell)LScape.get_landcell(envCellID);

                EnvCells.Add(new R_EnvCell(envCell));
            }
        }
예제 #10
0
        public static float GetTerrainZ(this Position p)
        {
            var cellID   = GetOutdoorCell(p);
            var landcell = (LandCell)LScape.get_landcell(cellID);

            if (landcell == null)
            {
                return(p.Pos.Z);
            }

            Physics.Polygon walkable = null;
            if (!landcell.find_terrain_poly(p.Pos, ref walkable))
            {
                return(p.Pos.Z);
            }

            Vector3 terrainPos = p.Pos;

            walkable.Plane.set_height(ref terrainPos);

            return(terrainPos.Z);
        }
예제 #11
0
        /// <summary>
        /// Spawns the semi-randomized monsters scattered around the outdoors<para />
        /// This will be called from a separate task from our constructor. Use thread safety when interacting with this landblock.
        /// </summary>
        private void SpawnEncounters()
        {
            // get the encounter spawns for this landblock
            var encounters = DatabaseManager.World.GetCachedEncountersByLandblock(Id.Landblock);

            foreach (var encounter in encounters)
            {
                var wo = WorldObjectFactory.CreateNewWorldObject(encounter.WeenieClassId);

                if (wo == null)
                {
                    continue;
                }

                var xPos = Math.Clamp(encounter.CellX * 24.0f, 0.5f, 191.5f);
                var yPos = Math.Clamp(encounter.CellY * 24.0f, 0.5f, 191.5f);

                var pos = new Physics.Common.Position();
                pos.ObjCellID = (uint)(Id.Landblock << 16) | 1;
                pos.Frame     = new Physics.Animation.AFrame(new Vector3(xPos, yPos, 0), Quaternion.Identity);
                pos.adjust_to_outside();

                pos.Frame.Origin.Z = _landblock.GetZ(pos.Frame.Origin);

                wo.Location = new Position(pos.ObjCellID, pos.Frame.Origin, pos.Frame.Orientation);

                var sortCell = LScape.get_landcell(pos.ObjCellID) as SortCell;
                if (sortCell != null && sortCell.has_building())
                {
                    continue;
                }

                actionQueue.EnqueueAction(new ActionEventDelegate(() =>
                {
                    AddWorldObject(wo);
                }));
            }
        }
예제 #12
0
        private void AddWorldObjectInternal(WorldObject wo)
        {
            Log($"adding {wo.Guid.Full:X}");

            if (!worldObjects.ContainsKey(wo.Guid))
            {
                worldObjects[wo.Guid] = wo;
            }

            wo.SetParent(this);

            wo.PhysicsObj.Position.Frame.Origin      = wo.Location.Pos;
            wo.PhysicsObj.Position.Frame.Orientation = wo.Location.Rotation;

            //wo.AdjustDungeonCells(wo.Location);

            var cell = LScape.get_landcell(wo.Location.Cell);

            if (cell != null)
            {
                wo.PhysicsObj.enter_cell(cell);
                wo.PhysicsObj.add_shadows_to_cell(cell);
            }

            // var args = BroadcastEventArgs.CreateAction(BroadcastAction.AddOrUpdate, wo);
            // Broadcast(args, true, Quadrant.All);
            // Alert all nearby players of the object
            EnqueueActionBroadcast(wo.Location, MaxObjectRange, (Player p) => p.TrackObject(wo));

            // if this is a player, tell them about everything else we have in range of them.
            if (wo is Player)
            {
                List <WorldObject> wolist = null;
                wolist = GetWorldObjectsInRange(wo, MaxObjectRange);
                AddPlayerTracking(wolist, ((Player)wo));
            }
        }
예제 #13
0
        public Landblock(LandblockId id)
        {
            Id = id;

            UpdateStatus(LandBlockStatusFlag.IdleUnloaded);

            // initialize adjacency array
            adjacencies.Add(Adjacency.North, null);
            adjacencies.Add(Adjacency.NorthEast, null);
            adjacencies.Add(Adjacency.East, null);
            adjacencies.Add(Adjacency.SouthEast, null);
            adjacencies.Add(Adjacency.South, null);
            adjacencies.Add(Adjacency.SouthWest, null);
            adjacencies.Add(Adjacency.West, null);
            adjacencies.Add(Adjacency.NorthWest, null);

            UpdateStatus(LandBlockStatusFlag.IdleLoading);

            actionQueue = new NestedActionQueue(WorldManager.ActionQueue);

            var objects = DatabaseManager.World.GetCachedInstancesByLandblock(Id.Landblock); // Instances

            var factoryObjects = WorldObjectFactory.CreateNewWorldObjects(objects);

            factoryObjects.ForEach(fo =>
            {
                AddWorldObject(fo);
                fo.ActivateLinks();
            });

            _landblock = LScape.get_landblock(Id.Raw);

            // Many thanks for GDL cache and GDL coding for loading into landblock and gmriggs assistance with taking the byte arrays and turning them in to more easy to follow (for me) data structures
            var encounters = DatabaseManager.World.GetCachedEncountersByLandblock(Id.Landblock);

            encounters.ForEach(encounter =>
            {
                var wo = WorldObjectFactory.CreateNewWorldObject(encounter.WeenieClassId);

                if (wo != null)
                {
                    float x_shift = 24.0f * encounter.CellX;
                    float y_shift = 24.0f * encounter.CellY;

                    var pos       = new Physics.Common.Position();
                    pos.ObjCellID = (uint)(id.Landblock << 16) | 1;
                    pos.Frame     = new Physics.Animation.AFrame(new Vector3(x_shift, y_shift, 0), new Quaternion(0, 0, 0, 1));
                    pos.adjust_to_outside();

                    pos.Frame.Origin.Z = _landblock.GetZ(pos.Frame.Origin);

                    wo.Location = new Position(pos.ObjCellID, pos.Frame.Origin.X, pos.Frame.Origin.Y, pos.Frame.Origin.Z, pos.Frame.Orientation.X, pos.Frame.Orientation.Y, pos.Frame.Orientation.Z, pos.Frame.Orientation.W);

                    if (!worldObjects.ContainsKey(wo.Guid))
                    {
                        AddWorldObject(wo);
                    }
                }
            });


            //LoadMeshes(objects);

            UpdateStatus(LandBlockStatusFlag.IdleLoaded);

            // FIXME(ddevec): Goal: get rid of UseTime() function...
            actionQueue.EnqueueAction(new ActionEventDelegate(() => UseTimeWrapper()));

            motionQueue = new NestedActionQueue(WorldManager.MotionQueue);
        }
예제 #14
0
        public async void LoadLandblocks(Vector2 startBlock, Vector2 endBlock)
        {
            //Console.WriteLine($"LoadLandblocks({startBlock}, {endBlock})");
            if (PlayerMode)
            {
                ExitPlayerMode();
                InitPlayerMode = true;
            }

            Render.Buffer.ClearBuffer();
            Server.Init();
            TextureCache.Init();

            LScape.unload_landblocks_all();

            DungeonMode = false;

            var dx        = (int)(endBlock.X - startBlock.X) + 1;
            var dy        = (int)(startBlock.Y - endBlock.Y) + 1;
            var numBlocks = dx * dy;

            var size        = endBlock - startBlock;
            var center      = startBlock + size / 2;
            var centerX     = (uint)Math.Round(center.X);
            var centerY     = (uint)Math.Round(center.Y);
            var landblockID = centerX << 24 | centerY << 16 | 0xFFFF;

            MainWindow.Status.WriteLine($"Loading {numBlocks} landblocks");
            await Task.Delay(1);

            //Landblocks = new Dictionary<uint, R_Landblock>();
            R_Landblock r_landblock = null;
            R_Landblock centerBlock = null;

            for (var lbx = (uint)startBlock.X; lbx <= endBlock.X; lbx++)
            {
                if (lbx < 0 || lbx > 254)
                {
                    continue;
                }

                for (var lby = (uint)endBlock.Y; lby <= startBlock.Y; lby++)
                {
                    if (lby < 0 || lby > 254)
                    {
                        continue;
                    }

                    var lbid = lbx << 24 | lby << 16 | 0xFFFF;

                    var timer     = Stopwatch.StartNew();
                    var landblock = LScape.get_landblock(lbid);
                    timer.Stop();

                    r_landblock = new R_Landblock(landblock);
                    //LScape.unload_landblock(lbid);

                    if (lbid == landblockID)
                    {
                        centerBlock = r_landblock;
                    }

                    MainWindow.Status.WriteLine($"Loaded {lbid:X8} in {timer.Elapsed.TotalMilliseconds}ms");

                    //Landblocks.Add(lbid, new R_Landblock(landblock));
                }
            }

            Render.Buffer.BuildBuffers();
            Render.InitEmitters();

            Camera.InitLandblock(centerBlock);
            GameView.ViewMode = ViewMode.World;

            SingleBlock = uint.MaxValue;

            FreeResources();

            Server.OnLoadWorld();
        }
예제 #15
0
        /// <summary>
        /// Used by physics engine to actually update a player position
        /// Automatically notifies clients of updated position
        /// </summary>
        /// <param name="newPosition">The new position being requested, before verification through physics engine</param>
        /// <returns>TRUE if object moves to a different landblock</returns>
        public bool UpdatePlayerPhysics(ACE.Entity.Position newPosition, bool forceUpdate = false)
        {
            //Console.WriteLine($"{Name}.UpdatePlayerPhysics({newPosition}, {forceUpdate}, {Teleporting})");

            // possible bug: while teleporting, client can still send AutoPos packets from old landblock
            if (Teleporting && !forceUpdate)
            {
                return(false);
            }

            // pre-validate movement
            if (!ValidateMovement(newPosition))
            {
                log.Error($"{Name}.UpdatePlayerPhysics() - movement pre-validation failed from {Location} to {newPosition}");
                return(false);
            }

            try
            {
                if (!forceUpdate) // This is needed beacuse this function might be called recursively
                {
                    stopwatch.Restart();
                }

                var success = true;

                if (PhysicsObj != null)
                {
                    var distSq = Location.SquaredDistanceTo(newPosition);

                    if (distSq > PhysicsGlobals.EpsilonSq)
                    {
                        var curCell = LScape.get_landcell(newPosition.Cell);
                        if (curCell != null)
                        {
                            //if (PhysicsObj.CurCell == null || curCell.ID != PhysicsObj.CurCell.ID)
                            //PhysicsObj.change_cell_server(curCell);

                            PhysicsObj.set_request_pos(newPosition.Pos, newPosition.Rotation, curCell, Location.LandblockId.Raw);
                            success = PhysicsObj.update_object_server();

                            if (PhysicsObj.CurCell == null && curCell.ID >> 16 != 0x18A)
                            {
                                PhysicsObj.CurCell = curCell;
                            }

                            CheckMonsters();
                        }
                    }
                }

                // double update path: landblock physics update -> updateplayerphysics() -> update_object_server() -> Teleport() -> updateplayerphysics() -> return to end of original branch
                if (Teleporting && !forceUpdate)
                {
                    return(true);
                }

                if (!success)
                {
                    return(false);
                }

                var landblockUpdate = Location.Cell >> 16 != newPosition.Cell >> 16;
                Location = newPosition;

                SendUpdatePosition();

                if (!InUpdate)
                {
                    LandblockManager.RelocateObjectForPhysics(this, true);
                }

                return(landblockUpdate);
            }
            finally
            {
                if (!forceUpdate) // This is needed beacuse this function might be called recursively
                {
                    var elapsedSeconds = stopwatch.Elapsed.TotalSeconds;
                    ServerPerformanceMonitor.AddToCumulativeEvent(ServerPerformanceMonitor.CumulativeEventHistoryType.WorldObject_Tick_UpdatePlayerPhysics, elapsedSeconds);
                    if (elapsedSeconds >= 1) // Yea, that ain't good....
                    {
                        log.Warn($"[PERFORMANCE][PHYSICS] {Guid}:{Name} took {(elapsedSeconds * 1000):N1} ms to process UpdatePlayerPhysics() at loc: {Location}");
                    }
                    else if (elapsedSeconds >= 0.010)
                    {
                        log.Debug($"[PERFORMANCE][PHYSICS] {Guid}:{Name} took {(elapsedSeconds * 1000):N1} ms to process UpdatePlayerPhysics() at loc: {Location}");
                    }
                }
            }
        }
예제 #16
0
        public void LoadModel(uint wcid)
        {
            Server.Initting = true;

            Buffer.ClearBuffer();
            TextureCache.Init();

            LScape.unload_landblocks_all();

            Console.WriteLine($"Loading {wcid}");
            GfxObjMode = false;

            var wo = WorldObjectFactory.CreateNewWorldObject(wcid);

            if (wo == null)
            {
                return;
            }

            wo.InitPhysicsObj();

            var location = new Position();

            location.ObjCellID    = 0x00000001;
            location.Frame.Origin = new System.Numerics.Vector3(12, 12, 0);

            var success = wo.PhysicsObj.enter_world(location);

            if (!success || wo.PhysicsObj.CurCell == null)
            {
                wo.PhysicsObj.DestroyObject();
                wo.PhysicsObj = null;
                Console.WriteLine($"WorldObjectViewer.LoadModel({wcid}).AddPhysicsObj({wo.Name}, {location}) - failed to spawn");
                return;
            }

            Console.WriteLine($"Spawned {wcid} - {wo.Name} @ {location}");

            var objDesc = new ObjDesc(wo.SetupTableId, wo.ClothingBase ?? 0, (PaletteTemplate)(wo.PaletteTemplate ?? 0), (float)(wo.Shade ?? 0.0));

            if (wo is Creature creature)
            {
                objDesc.AddBaseModelData(wo);

                var equippedObjects = creature.EquippedObjects.Values.OrderBy(i => (int)(i.ClothingPriority ?? 0)).ToList();

                foreach (var equippedObject in equippedObjects)
                {
                    if ((equippedObject.CurrentWieldedLocation & EquipMask.Selectable) != 0)
                    {
                        continue;
                    }

                    objDesc.Add(equippedObject.ClothingBase ?? 0, (PaletteTemplate)(equippedObject.PaletteTemplate ?? 0), (float)(equippedObject.Shade ?? 0.0));
                }
            }

            wo.PhysicsObj.UpdateObjDesc(objDesc);

            var r_PhysicsObj = new R_PhysicsObj(wo.PhysicsObj);

            Buffer.AddInstance(r_PhysicsObj, objDesc);

            if (!LoadedOnce)
            {
                //Camera.Position = Vector3.Zero;
                //Camera.Dir = Vector3.Normalize(new Vector3(1, 1, 0));

                Camera.Position = new Vector3(11.782367f, 12.763985f, 1.6514041f);
                Camera.Dir      = new Vector3(0.30761153f, -0.94673103f, 0.093334414f);
                Camera.Up       = Vector3.UnitZ;

                Camera.CreateLookAt();

                Camera.Speed = Camera.Model_Speed;
            }

            Buffer.BuildTextureAtlases(Buffer.InstanceTextureAtlasChains);
            Buffer.BuildBuffer(Buffer.RB_Instances);
            Server.InstancesLoaded = true;
            Server.Initting        = false;

            LoadedOnce = true;
        }
예제 #17
0
        public void LoadLandblock(uint landblockID, uint radius = 1)
        {
            if (PlayerMode)
            {
                ExitPlayerMode();
                InitPlayerMode = true;
            }

            Render.Buffer.ClearBuffer();
            Server.Init();
            TextureCache.Init();

            LScape.unload_landblocks_all();

            var landblock = LScape.get_landblock(landblockID);

            if (landblock.HasDungeon)
            {
                radius = 0;
            }

            DungeonMode = landblock.HasDungeon;

            var center_lbx = landblockID >> 24;
            var center_lby = landblockID >> 16 & 0xFF;

            //Landblocks = new Dictionary<uint, R_Landblock>();
            R_Landblock r_landblock = null;
            R_Landblock centerBlock = null;

            for (var lbx = (int)(center_lbx - radius); lbx <= center_lbx + radius; lbx++)
            {
                if (lbx < 0 || lbx > 254)
                {
                    continue;
                }

                for (var lby = (int)(center_lby - radius); lby <= center_lby + radius; lby++)
                {
                    if (lby < 0 || lby > 254)
                    {
                        continue;
                    }

                    var lbid = (uint)(lbx << 24 | lby << 16 | 0xFFFF);

                    var timer = Stopwatch.StartNew();
                    landblock = LScape.get_landblock(lbid);
                    timer.Stop();

                    r_landblock = new R_Landblock(landblock);
                    //LScape.unload_landblock(lbid);

                    if (landblockID == lbid)
                    {
                        centerBlock = r_landblock;
                    }

                    MainWindow.Status.WriteLine($"Loaded {lbid:X8} in {timer.Elapsed.TotalMilliseconds}ms");

                    //Landblocks.Add(lbid, new R_Landblock(landblock));
                }
            }

            Render.Buffer.BuildBuffers();
            Render.InitEmitters();

            if (FileExplorer.Instance.TeleportMode)
            {
                var zBump = DungeonMode ? 1.775f : 2.775f;

                if (InitPlayerMode)
                {
                    zBump = 0.0f;
                }

                Camera.InitTeleport(centerBlock, zBump);
                FileExplorer.Instance.TeleportMode = false;
            }
            else if (DungeonMode)
            {
                BoundingBox = new Model.BoundingBox(Render.Buffer.RB_EnvCell);
                Camera.InitDungeon(r_landblock, BoundingBox);
            }
            else
            {
                Camera.InitLandblock(r_landblock);
            }

            SingleBlock = landblock.ID;

            FreeResources();

            Server.OnLoadWorld();
        }
예제 #18
0
        /// <summary>
        /// Used by physics engine to actually update a player position
        /// Automatically notifies clients of updated position
        /// </summary>
        /// <param name="newPosition">The new position being requested, before verification through physics engine</param>
        /// <returns>TRUE if object moves to a different landblock</returns>
        public bool UpdatePlayerPhysics(ACE.Entity.Position newPosition, bool forceUpdate = false)
        {
            //Console.WriteLine($"UpdatePlayerPhysics: {newPosition.Cell:X8}, {newPosition.Pos}");

            var player = this as Player;

            // only handles player movement
            if (player == null)
            {
                return(false);
            }

            // possible bug: while teleporting, client can still send AutoPos packets from old landblock
            if (Teleporting && !forceUpdate)
            {
                return(false);
            }

            if (PhysicsObj != null)
            {
                var dist = (newPosition.Pos - PhysicsObj.Position.Frame.Origin).Length();
                if (dist > PhysicsGlobals.EPSILON)
                {
                    var curCell = LScape.get_landcell(newPosition.Cell);
                    if (curCell != null)
                    {
                        //if (PhysicsObj.CurCell == null || curCell.ID != PhysicsObj.CurCell.ID)
                        //PhysicsObj.change_cell_server(curCell);

                        PhysicsObj.set_request_pos(newPosition.Pos, newPosition.Rotation, curCell, Location.LandblockId.Raw);
                        PhysicsObj.update_object_server();

                        if (PhysicsObj.CurCell == null)
                        {
                            PhysicsObj.CurCell = curCell;
                        }

                        player.CheckMonsters();

                        if (curCell.ID != prevCell)
                        {
                            //prevCell = curCell.ID;
                            //Console.WriteLine("Player cell: " + curCell.ID.ToString("X8"));
                            //var envCell = curCell as Physics.Common.EnvCell;
                            //var seenOutside = envCell != null ? envCell.SeenOutside : true;
                            //Console.WriteLine($"CurCell: {curCell.ID:X8}, SeenOutside: {seenOutside}");
                        }
                    }
                }
            }

            // double update path: landblock physics update -> updateplayerphysics() -> update_object_server() -> Teleport() -> updateplayerphysics() -> return to end of original branch
            if (Teleporting && !forceUpdate)
            {
                return(true);
            }

            var landblockUpdate = Location.Cell >> 16 != newPosition.Cell >> 16;

            Location = newPosition;

            SendUpdatePosition();

            if (!InUpdate)
            {
                LandblockManager.RelocateObjectForPhysics(this, true);
            }

            return(landblockUpdate);
        }
예제 #19
0
        public void ProcessGeneratorQueue()
        {
            var index = 0;

            while (index < GeneratorQueue.Count)
            {
                double ts = Common.Time.GetTimestamp();
                if (ts >= GeneratorQueue[index].When)
                {
                    if (GeneratorRegistry.Count >= MaxGeneratedObjects)
                    {
                        // System.Diagnostics.Debug.WriteLine($"GeneratorRegistry for {Guid.Full} is at MaxGeneratedObjects {MaxGeneratedObjects}");
                        // System.Diagnostics.Debug.WriteLine($"Removing {GeneratorQueue[index].Slot} from GeneratorQueue for {Guid.Full}");
                        GeneratorQueue.RemoveAt(index);
                        index++;
                        continue;
                    }
                    var profile = GeneratorProfiles[(int)GeneratorQueue[index].Slot];

                    var rNode = new GeneratorRegistryNode();

                    rNode.WeenieClassId = profile.WeenieClassId;
                    rNode.Timestamp     = Common.Time.GetTimestamp();
                    rNode.Slot          = GeneratorQueue[index].Slot;

                    var wo = WorldObjectFactory.CreateNewWorldObject(profile.WeenieClassId);

                    if (wo != null)
                    {
                        switch ((RegenLocationType)profile.WhereCreate)
                        {
                        case RegenLocationType.SpecificTreasure:
                        case RegenLocationType.Specific:
                            if ((profile.ObjCellId ?? 0) > 0)
                            {
                                wo.Location = new ACE.Entity.Position(profile.ObjCellId ?? 0,
                                                                      profile.OriginX ?? 0, profile.OriginY ?? 0, profile.OriginZ ?? 0,
                                                                      profile.AnglesX ?? 0, profile.AnglesY ?? 0, profile.AnglesZ ?? 0, profile.AnglesW ?? 0);
                            }
                            else
                            {
                                wo.Location = new ACE.Entity.Position(Location.Cell,
                                                                      Location.PositionX + profile.OriginX ?? 0, Location.PositionY + profile.OriginY ?? 0, Location.PositionZ + profile.OriginZ ?? 0,
                                                                      profile.AnglesX ?? 0, profile.AnglesY ?? 0, profile.AnglesZ ?? 0, profile.AnglesW ?? 0);
                            }
                            break;

                        case RegenLocationType.ScatterTreasure:
                        case RegenLocationType.Scatter:
                            float genRadius = (float)(GetProperty(PropertyFloat.GeneratorRadius) ?? 0f);
                            var   random_x  = Physics.Common.Random.RollDice(genRadius * -1, genRadius);
                            var   random_y  = Physics.Common.Random.RollDice(genRadius * -1, genRadius);
                            var   pos       = new Physics.Common.Position(Location);
                            wo.Location = new ACE.Entity.Position(pos.ObjCellID, pos.Frame.Origin.X, pos.Frame.Origin.Y, pos.Frame.Origin.Z, pos.Frame.Orientation.X, pos.Frame.Orientation.Y, pos.Frame.Orientation.Z, pos.Frame.Orientation.W);
                            var newPos = wo.Location.Pos + new Vector3(random_x, random_y, 0.0f);
                            if (!Location.Indoors)
                            {
                                // Based on GDL scatter
                                newPos.X = Math.Clamp(newPos.X, 0.5f, 191.5f);
                                newPos.Y = Math.Clamp(newPos.Y, 0.5f, 191.5f);
                                wo.Location.SetPosition(newPos);
                                newPos.Z = LScape.get_landblock(wo.Location.Cell).GetZ(newPos);
                            }
                            wo.Location.SetPosition(newPos);
                            break;

                        default:
                            wo.Location = Location;
                            break;
                        }

                        wo.Generator   = this;
                        wo.GeneratorId = Guid.Full;

                        // System.Diagnostics.Debug.WriteLine($"Adding {wo.Guid.Full} | {rNode.Slot} in GeneratorRegistry for {Guid.Full}");
                        GeneratorRegistry.Add(wo.Guid.Full, rNode);
                        GeneratorCache.Add(wo.Guid.Full, wo);
                        // System.Diagnostics.Debug.WriteLine($"Spawning {GeneratorQueue[index].Slot} in GeneratorQueue for {Guid.Full}");
                        wo.EnterWorld();
                        // System.Diagnostics.Debug.WriteLine($"Removing {GeneratorQueue[index].Slot} from GeneratorQueue for {Guid.Full}");
                        GeneratorQueue.RemoveAt(index);
                    }
                    else
                    {
                        // System.Diagnostics.Debug.WriteLine($"Removing {GeneratorQueue[index].Slot} from GeneratorQueue for {Guid.Full} because wcid {rNode.WeenieClassId} is not in the database");
                        GeneratorQueue.RemoveAt(index);
                    }
                }
                else
                {
                    index++;
                }
            }
        }
예제 #20
0
        /// <summary>
        /// Used by physics engine to actually update a player position
        /// Automatically notifies clients of updated position
        /// </summary>
        /// <param name="newPosition">The new position being requested, before verification through physics engine</param>
        /// <returns>TRUE if object moves to a different landblock</returns>
        public bool UpdatePlayerPosition(ACE.Entity.Position newPosition, bool forceUpdate = false)
        {
            //Console.WriteLine($"{Name}.UpdatePlayerPhysics({newPosition}, {forceUpdate}, {Teleporting})");
            bool verifyContact = false;

            // possible bug: while teleporting, client can still send AutoPos packets from old landblock
            if (Teleporting && !forceUpdate)
            {
                return(false);
            }

            // pre-validate movement
            if (!ValidateMovement(newPosition))
            {
                log.Error($"{Name}.UpdatePlayerPosition() - movement pre-validation failed from {Location} to {newPosition}");
                return(false);
            }

            try
            {
                if (!forceUpdate) // This is needed beacuse this function might be called recursively
                {
                    stopwatch.Restart();
                }

                var success = true;

                if (PhysicsObj != null)
                {
                    var distSq = Location.SquaredDistanceTo(newPosition);

                    if (distSq > PhysicsGlobals.EpsilonSq)
                    {
                        /*var p = new Physics.Common.Position(newPosition);
                         * var dist = PhysicsObj.Position.Distance(p);
                         * Console.WriteLine($"Dist: {dist}");*/

                        if (newPosition.Landblock == 0x18A && Location.Landblock != 0x18A)
                        {
                            log.Info($"{Name} is getting swanky");
                        }

                        if (!Teleporting)
                        {
                            var blockDist = PhysicsObj.GetBlockDist(Location.ObjCellID, newPosition.ObjCellID);

                            // verify movement
                            if (distSq > MaxSpeedSq && blockDist > 1)
                            {
                                //Session.Network.EnqueueSend(new GameMessageSystemChat("Movement error", ChatMessageType.Broadcast));
                                log.Warn($"MOVEMENT SPEED: {Name} trying to move from {Location} to {newPosition}, speed: {Math.Sqrt(distSq)}");
                                return(false);
                            }

                            // verify z-pos
                            if (blockDist == 0 && LastGroundPos != null && newPosition.Pos.Z - LastGroundPos.Pos.Z > 10 && DateTime.UtcNow - LastJumpTime > TimeSpan.FromSeconds(1) && GetCreatureSkill(Skill.Jump).Current < 1000)
                            {
                                verifyContact = true;
                            }
                        }

                        var curCell = LScape.get_landcell(newPosition.LongObjCellID);
                        if (curCell != null)
                        {
                            //if (PhysicsObj.CurCell == null || curCell.ID != PhysicsObj.CurCell.ID)
                            //PhysicsObj.change_cell_server(curCell);

                            PhysicsObj.set_request_pos(newPosition.Pos, newPosition.Rotation, newPosition.Instance, curCell, Location.ObjCellID);
                            if (FastTick)
                            {
                                success = PhysicsObj.update_object_server_new(true, newPosition.Instance);
                            }
                            else
                            {
                                success = PhysicsObj.update_object_server(true, newPosition.Instance);
                            }

                            if (PhysicsObj.CurCell == null && curCell.ID >> 16 != 0x18A)
                            {
                                PhysicsObj.CurCell = curCell;
                            }

                            if (verifyContact && IsJumping)
                            {
                                log.Warn($"z-pos hacking detected for {Name}, lastGroundPos: {LastGroundPos.ToLOCString()} - requestPos: {newPosition.ToLOCString()}");
                                Location = new ACE.Entity.Position(LastGroundPos);
                                Sequences.GetNextSequence(SequenceType.ObjectForcePosition);
                                SendUpdatePosition();
                                return(false);
                            }

                            CheckMonsters();
                        }
                    }
                    else
                    {
                        PhysicsObj.Position.Frame.Orientation = newPosition.Rotation;
                    }
                }

                // double update path: landblock physics update -> updateplayerphysics() -> update_object_server() -> Teleport() -> updateplayerphysics() -> return to end of original branch
                if (Teleporting && !forceUpdate)
                {
                    return(true);
                }

                if (!success)
                {
                    return(false);
                }

                var landblockUpdate = Location.Landblock != newPosition.Landblock;

                Location = newPosition;

                if (RecordCast.Enabled)
                {
                    RecordCast.Log($"CurPos: {Location.ToLOCString()}");
                }

                if (RequestedLocationBroadcast || DateTime.UtcNow - LastUpdatePosition >= MoveToState_UpdatePosition_Threshold)
                {
                    SendUpdatePosition();
                }
                else
                {
                    Session.Network.EnqueueSend(new GameMessageUpdatePosition(this));
                }

                if (!InUpdate)
                {
                    // todo: improve this logic

                    /*if (CurrentLandblock.Instance > 0)
                     * {
                     *  ClearInstance(CurrentLandblock.LongId);
                     * }*/

                    LandblockManager.RelocateObjectForPhysics(this, true);
                }

                return(landblockUpdate);
            }
            finally
            {
                if (!forceUpdate) // This is needed beacuse this function might be called recursively
                {
                    var elapsedSeconds = stopwatch.Elapsed.TotalSeconds;
                    ServerPerformanceMonitor.AddToCumulativeEvent(ServerPerformanceMonitor.CumulativeEventHistoryType.Player_Tick_UpdateObjectPhysics, elapsedSeconds);
                    if (elapsedSeconds >= 0.100) // Yea, that ain't good....
                    {
                        log.Warn($"[PERFORMANCE][PHYSICS] {Guid}:{Name} took {(elapsedSeconds * 1000):N1} ms to process UpdatePlayerPosition() at loc: {Location}");
                    }
                    else if (elapsedSeconds >= 0.010)
                    {
                        log.Debug($"[PERFORMANCE][PHYSICS] {Guid}:{Name} took {(elapsedSeconds * 1000):N1} ms to process UpdatePlayerPosition() at loc: {Location}");
                    }
                }
            }
        }
        /// <summary>
        /// Gets the cell ID for a position within a landblock
        /// </summary>
        public static uint GetCell(this Position p)
        {
            var landblock = LScape.get_landblock(p.LongObjCellID);

            // dungeons
            // TODO: investigate dungeons that are below actual traversable overworld terrain
            // ex., 010AFFFF
            //if (landblock.IsDungeon)
            if (p.Indoors)
            {
                return(GetIndoorCell(p));
            }

            // outside - could be on landscape, in building, or underground cave
            var cellID     = GetOutdoorCell(p);
            var longcellID = ((ulong)p.Instance << 32) | cellID;
            var landcell   = LScape.get_landcell(longcellID) as LandCell;

            if (landcell == null)
            {
                return(cellID);
            }

            if (landcell.has_building())
            {
                var envCells = landcell.Building.get_building_cells();
                foreach (var envCell in envCells)
                {
                    if (envCell.point_in_cell(p.Pos))
                    {
                        return(envCell.ID);
                    }
                }
            }

            // handle underground areas ie. caves
            // get the terrain Z-height for this X/Y
            Physics.Polygon walkable    = null;
            var             terrainPoly = landcell.find_terrain_poly(p.Pos, ref walkable);

            if (walkable != null)
            {
                Vector3 terrainPos = p.Pos;
                walkable.Plane.set_height(ref terrainPos);

                // are we below ground? if so, search all of the indoor cells for this landblock
                if (terrainPos.Z > p.Pos.Z)
                {
                    var envCells = landblock.get_envcells();
                    foreach (var envCell in envCells)
                    {
                        if (envCell.point_in_cell(p.Pos))
                        {
                            return(envCell.ID);
                        }
                    }
                }
            }

            return(cellID);
        }
예제 #22
0
파일: Picker.cs 프로젝트: OptimShi/ACViewer
        public static void TryFindObject(Vector3 dir)
        {
            Dir = dir;

            LastPickResult = PickResult;

            ClearSelection();

            PickResult = new PickResult();

            // first try using physics engine for this

            // try spawning a tiny 'projectile' object at the camera position

            // if successfully spawned, simulate proceeding in that direction until something is hit

            var startPos = Camera.GetPosition();

            if (startPos == null)
            {
                Console.WriteLine($"Couldn't find current camera position in world!");
                return;
            }

            var maxSteps = 500;
            var stepSize = 1.0f;
            var i        = 0;

            var stepDir = (dir * stepSize).ToNumerics();

            var singleBlock = WorldViewer.Instance.SingleBlock;

            if (singleBlock != uint.MaxValue)
            {
                var landblock = LScape.get_landblock(singleBlock);

                // custom for single landblock IsDungeon
                if (landblock.IsDungeon)
                {
                    if (startPos.Landblock != singleBlock >> 16)
                    {
                        startPos.Reframe(singleBlock);
                    }

                    var adjustCell = AdjustCell.Get(startPos.Landblock);

                    for ( ; i < maxSteps; i++)
                    {
                        var foundCell = adjustCell.GetCell(startPos.Frame.Origin);

                        if (foundCell != null)
                        {
                            startPos.ObjCellID = foundCell.Value;
                            break;
                        }
                        startPos.Frame.Origin += stepDir;
                    }
                }
            }

            // todo: make this static
            var pickerObj = PhysicsObj.makeObject(setupId, pickerGuid.Full, true);

            pickerObj.State |= PhysicsState.PathClipped;
            pickerObj.State &= ~PhysicsState.Gravity;

            pickerObj.set_object_guid(pickerGuid);

            var worldObj = new WorldObject();
            //worldObj.Name = "Picker";

            var weenie = new WeenieObject(worldObj);

            pickerObj.set_weenie_obj(weenie);

            // perform transition
            PhysicsObj.IsPicking = true;

            var showedMsg = false;

            var spawned = false;

            for ( ; i < maxSteps; i++)
            {
                if (!spawned)
                {
                    var success = pickerObj.enter_world(startPos);

                    if (!success)
                    {
                        startPos.Frame.Origin += stepDir;
                        continue;
                    }
                    else
                    {
                        //Console.WriteLine($"Successfully spawned picker @ {startPos}");
                        spawned = true;
                    }
                }

                var nextPos = new ACE.Server.Physics.Common.Position(pickerObj.Position);

                nextPos.Frame.Origin += stepDir;

                var transition = pickerObj.transition(pickerObj.Position, nextPos, false);

                // debug collision info
                if (transition == null)
                {
                    Console.WriteLine($"Null transition result!");
                    showedMsg = true;
                    break;
                }
                else if (transition.CollisionInfo.CollidedWithEnvironment || transition.CollisionInfo.CollideObject.Count > 0)
                {
                    /*if (transition.CollisionInfo.CollidedWithEnvironment)
                     *  Console.WriteLine($"CollidedWithEnvironment");
                     *
                     * if (transition.CollisionInfo.CollideObject.Count > 0)
                     * {
                     *  Console.WriteLine($"CollideObjs:");
                     *  foreach (var collideObj in transition.CollisionInfo.CollideObject)
                     *      Console.WriteLine($"{collideObj.PartArray.Setup._dat.Id:X8} @ {collideObj.Position.ShortLoc()}");
                     * }*/

                    BuildHitPolys();
                    showedMsg = true;
                    break;
                }
                else
                {
                    pickerObj.SetPositionInternal(transition);
                }
            }

            PhysicsObj.IsPicking = false;

            if (!spawned)
            {
                Console.WriteLine($"Failed to spawn picker @ {Camera.GetPosition()}");
            }
            else if (!showedMsg)
            {
                Console.WriteLine($"No collisions");
            }

            // cleanup
            pickerObj.DestroyObject();
        }
예제 #23
0
파일: Server.cs 프로젝트: OptimShi/ACViewer
        public static void LoadEncounters()
        {
            Initting = true;
            MainWindow.Instance.SuppressStatusText = true;

            SetDatabaseConfig();

            Encounters = new List <WorldObject>();

            var timer = Stopwatch.StartNew();

            // get the list of loaded landblocks
            foreach (var lbid in LScape.Landblocks.Keys)
            {
                var encounters = DatabaseManager.World.GetCachedEncountersByLandblock((ushort)(lbid >> 16));

                Console.WriteLine($"Found {encounters.Count:N0} encounters for {lbid:X8}");

                var landblock = LScape.get_landblock(lbid);

                foreach (var encounter in encounters)
                {
                    var wo = WorldObjectFactory.CreateNewWorldObject(encounter.WeenieClassId);

                    if (wo == null)
                    {
                        continue;
                    }

                    wo.InitPhysicsObj();

                    var xPos = Math.Clamp(encounter.CellX * 24.0f, 0.5f, 191.5f);
                    var yPos = Math.Clamp(encounter.CellY * 24.0f, 0.5f, 191.5f);

                    var pos = new Position();
                    pos.ObjCellID = lbid & 0xFFFF0000 | 1;
                    pos.Frame     = new AFrame(new Vector3(xPos, yPos, 0), Quaternion.Identity);
                    pos.adjust_to_outside();

                    pos.Frame.Origin.Z = landblock.GetZ(pos.Frame.Origin);

                    wo.Location = new ACE.Entity.Position(pos.ObjCellID, pos.Frame.Origin, pos.Frame.Orientation);

                    var sortCell = LScape.get_landcell(pos.ObjCellID) as SortCell;
                    if (sortCell != null && sortCell.has_building())
                    {
                        continue;
                    }

                    var success = wo.AddPhysicsObj(pos);

                    if (!success)
                    {
                        Console.WriteLine($"LoadEncounters({lbid:X8}).AddPhysicsObj({wo.Name}, {pos}) - failed to spawn");
                        continue;
                    }

                    Console.WriteLine($"Spawned {encounter.WeenieClassId} - {wo.Name} @ {pos}");

                    AddEncounter(wo);
                }
            }

            TickGenerators(GeneratorTickMode.Encounters);

            timer.Stop();

            Console.WriteLine($"Completed in {timer.Elapsed.TotalSeconds}s");
        }