Ticket #3280: formation_pathfinding.2.diff
File formation_pathfinding.2.diff, 27.1 KB (added by , 9 years ago) |
---|
-
binaries/data/mods/public/simulation/components/Formation.js
548 548 xMin = Math.min(xMin, offset.x); 549 549 yMin = Math.min(yMin, offset.y); 550 550 } 551 this.width = xMax - xMin; 552 this.depth = yMax - yMin; 551 this.width = xMax - xMin + 4;// TODO take formation width + passClass clearance 552 this.depth = yMax - yMin + 4; 553 554 // set an obstruction size to calculate collisions 555 var cmpObstruction = Engine.QueryInterface(this.entity, IID_Obstruction); 556 if (cmpObstruction) 557 cmpObstruction.SetSize(this.depth, this.width); 558 var cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); 559 if (cmpUnitMotion) 560 cmpUnitMotion.SetAllowedDeviation(this.width); 553 561 }; 554 562 555 563 Formation.prototype.MoveToMembersCenter = function() … … 878 886 { 879 887 var maxRadius = 0; 880 888 var minSpeed = Infinity; 889 var runSpeed = 0; 881 890 882 891 for each (var ent in this.members) 883 892 { … … 887 896 888 897 var cmpUnitMotion = Engine.QueryInterface(ent, IID_UnitMotion); 889 898 if (cmpUnitMotion) 899 { 890 900 minSpeed = Math.min(minSpeed, cmpUnitMotion.GetWalkSpeed()); 901 runSpeed += cmpUnitMotion.GetRunSpeed(); 902 } 891 903 } 904 runSpeed /= this.members.length; 892 905 minSpeed *= this.GetSpeedMultiplier(); 893 906 894 907 var cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); 895 908 cmpUnitMotion.SetUnitRadius(maxRadius); 896 909 cmpUnitMotion.SetSpeed(minSpeed); 910 cmpUnitMotion.SetRunSpeed(runSpeed); 897 911 898 912 // TODO: we also need to do something about PassabilityClass, CostClass 899 913 }; -
binaries/data/mods/public/simulation/components/UnitMotionFormation.js
1 function UnitMotionFormation() {} 2 3 UnitMotionFormation.prototype.Schema = 4 "<empty/>"; 5 6 UnitMotionFormation.prototype.Init = function() 7 { 8 this.goal = null; 9 this.pathTicket = 0; 10 this.passClass = 0; 11 this.path = []; 12 this.speed = 1; 13 this.runSpeed = 1; 14 this.pathIdx = -1; 15 this.state = "IDLE"; 16 this.allowedDeviation = 8; 17 18 var cmpPathfinder = Engine.QueryInterface(SYSTEM_ENTITY, IID_Pathfinder); 19 this.passClass = cmpPathfinder.GetPassabilityClass("default"); 20 }; 21 22 UnitMotionFormation.prototype.SetPassabilityClassName = function(name) 23 { 24 var cmpPathfinder = Engine.QueryInterface(SYSTEM_ENTITY, IID_Pathfinder); 25 this.passClass = cmpPathfinder.GetPassabilityClass(name); 26 }; 27 28 // Ignore, unit radius is not important anymore, only the passability class is 29 UnitMotionFormation.prototype.SetUnitRadius = function() {}; 30 31 UnitMotionFormation.prototype.SetAllowedDeviation = function(allowedDeviation) 32 { 33 this.allowedDeviation = allowedDeviation; 34 }; 35 36 UnitMotionFormation.prototype.IsMoving = function() 37 { 38 return this.pathIdx >= 0; 39 }; 40 UnitMotionFormation.prototype.SetSpeed = function(speed) 41 { 42 this.speed = speed; 43 }; 44 UnitMotionFormation.prototype.SetRunSpeed = function(speed) 45 { 46 this.runSpeed = speed; 47 }; 48 UnitMotionFormation.prototype.MoveToPointRange = function(x, z, minRange, maxRange) 49 { 50 this.goal = { 51 "type": 0, 52 "x": x, // target x 53 "z": z, // target z 54 "u": {"x": 1, "y": 0}, // first unit axis 55 "v": {"x": 0, "y": 1}, // second unit axis 56 "hw": maxRange, // for a circle, hw is range 57 "hh": maxRange, 58 "maxdist": 0 // maxdist between waypoints, 0 -> unlimited 59 } 60 var cmpPosition = Engine.QueryInterface(this.entity, IID_Position); 61 if (!cmpPosition || !cmpPosition.IsInWorld()) 62 return false; 63 64 var pos = cmpPosition.GetPosition2D(); 65 66 var cmpPathfinder = Engine.QueryInterface(SYSTEM_ENTITY, IID_Pathfinder); 67 this.pathTicket = cmpPathfinder.ComputePathAsync(pos.x, pos.y, this.goal, this.passClass, this.entity); 68 69 this.state = "PATH_REQUESTED"; 70 return true; 71 }; 72 73 UnitMotionFormation.prototype.OnPathResult = function(msg) 74 { 75 if (msg.ticket != this.pathTicket) 76 return; 77 if (!msg.path.length) 78 return; 79 80 var cmpPosition = Engine.QueryInterface(this.entity, IID_Position); 81 if (!cmpPosition || !cmpPosition.IsInWorld()) 82 return; 83 84 var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); 85 if (!cmpFormation) 86 return; 87 // path generalisation 88 var size = Math.min(cmpFormation.GetSize().width, cmpFormation.GetSize().depth); 89 var pos = msg.path[0]; 90 this.path = [pos]; 91 for (var i = 1; i < msg.path.length; ++i) 92 { 93 var dx = pos.x - msg.path[i].x; 94 var dy = pos.y - msg.path[i].y; 95 if (dx * dx + dy * dy < size * size) 96 continue; 97 pos = msg.path[i]; 98 this.path.push(pos); 99 } 100 this.pathIdx = this.path.length - 1; 101 // add the current position for reference 102 pos = cmpPosition.GetPosition2D(); 103 this.path.push({"x" : pos.x, "y": pos.y}); 104 105 var direction = Vector2D.clone(this.path[this.pathIdx]).sub(pos); 106 cmpPosition.TurnTo(Math.atan2(direction.x, direction.y)); 107 108 this.state = "FOLLOW_LINE"; 109 Engine.PostMessage(this.entity, MT_MotionChanged, { "starting": true, "error": false }); 110 }; 111 112 UnitMotionFormation.prototype.OnUpdate = function(msg) 113 { 114 if (!this.IsMoving()) 115 return; 116 if (this.state == "FOLLOW_LINE") 117 this.FollowLine(msg.turnLength); 118 else if (this.state == "TAKE_TURN") 119 this.TakeTurn(msg.turnLength); 120 }; 121 122 UnitMotionFormation.prototype.FollowLine = function(turnLength) 123 { 124 var cmpPosition = Engine.QueryInterface(this.entity, IID_Position); 125 if (!cmpPosition || !cmpPosition.IsInWorld()) 126 return; 127 128 var pos = cmpPosition.GetPosition2D(); 129 130 // project current position to original path 131 var target = this.path[this.pathIdx]; 132 var source = this.path[this.pathIdx + 1]; 133 var direction = Vector2D.clone(target).sub(source); 134 var posVec = Vector2D.clone(pos).sub(source); 135 var pathPosition = Vector2D.clone(direction).mult(posVec.dot(direction) / direction.lengthSquared()); 136 137 // Get the distance on the original path 138 var pathToWalk = Vector2D.clone(direction).sub(pathPosition); 139 var distanceToTarget = pathToWalk.length(); 140 var distanceToWalk = this.speed * turnLength; 141 142 if (distanceToTarget < distanceToWalk) // just walk straight on, and start turning 143 { 144 pos.add(pathToWalk); 145 cmpPosition.MoveTo(pos.x, pos.y); 146 // if this is the last target, stop moving 147 if (this.pathIdx) 148 { 149 // else, take a turn 150 var usedTime = distanceToTarget / this.speed; 151 this.state = "TAKE_TURN"; 152 this.TakeTurn(turnLength - usedTime); 153 } 154 else 155 { 156 this.pathIdx--; 157 Engine.PostMessage(this.entity, MT_MotionChanged, { "starting": false, "error": false }); 158 this.state = "IDLE"; 159 } 160 return; 161 } 162 163 var currentDeviation = posVec.distanceTo(pathPosition); 164 if (this.pathIdx == 0 && distanceToTarget <= currentDeviation) 165 { 166 var pathToTarget = Vector2D.clone(target).sub(pos).normalize().mult(distanceToWalk); 167 pos.add(pathToTarget); 168 cmpPosition.MoveTo(pos.x, pos.y); 169 return; 170 } 171 172 // Find the next position 173 // scale the path to walk to include the walkable distance 174 var centerPathToWalk = Vector2D.clone(pathToWalk).mult(distanceToWalk / distanceToTarget); 175 // expand the rotation matrix for the 45deg rotations 176 var leftPathToWalk = new Vector2D(centerPathToWalk.x - centerPathToWalk.y, centerPathToWalk.x + centerPathToWalk.y); 177 var rightPathToWalk = new Vector2D(centerPathToWalk.x + centerPathToWalk.y, -centerPathToWalk.x + centerPathToWalk.y); 178 179 var newCenterPosVec = Vector2D.clone(posVec).add(centerPathToWalk); 180 var newLeftPosVec = Vector2D.clone(posVec).add(leftPathToWalk); 181 var newRightPosVec = Vector2D.clone(posVec).add(rightPathToWalk); 182 183 // project the center to the original path 184 var centerPathPosition = Vector2D.clone(direction).mult(newCenterPosVec.dot(direction) / direction.lengthSquared()); 185 186 var allowLeft = newLeftPosVec.distanceToSquared(centerPathPosition) < this.allowedDeviation * this.allowedDeviation; 187 var allowRight = newRightPosVec.distanceToSquared(centerPathPosition) < this.allowedDeviation * this.allowedDeviation; 188 189 // compare the obstructions 190 var cmpPathfinder = Engine.QueryInterface(SYSTEM_ENTITY, IID_Pathfinder); 191 var centerObstructedTiles = cmpPathfinder.GetObstructedTiles(centerPathToWalk, this.entity, this.passClass); 192 var leftObstructedTiles = Infinity; 193 var rightObstructedTiles = Infinity; 194 if (allowLeft) 195 leftObstructedTiles = cmpPathfinder.GetObstructedTiles(leftPathToWalk, this.entity, this.passClass); 196 if (allowRight) 197 rightObstructedTiles = cmpPathfinder.GetObstructedTiles(rightPathToWalk, this.entity, this.passClass); 198 199 // choose the best of the three positions 200 var min = Math.min(centerObstructedTiles, leftObstructedTiles, rightObstructedTiles); 201 if (min == centerObstructedTiles) 202 pos.add(centerPathToWalk); 203 else if (min == leftObstructedTiles) 204 pos.add(leftPathToWalk); 205 else if (min == rightObstructedTiles) 206 pos.add(rightPathToWalk); 207 208 cmpPosition.MoveTo(pos.x, pos.y); 209 }; 210 211 UnitMotionFormation.prototype.TakeTurn = function(turnLength) 212 { 213 var cmpPosition = Engine.QueryInterface(this.entity, IID_Position); 214 var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); 215 if (!cmpPosition || !cmpPosition.IsInWorld() || !cmpFormation) 216 return; 217 var formationSize = Math.max(cmpFormation.GetSize().width, cmpFormation.GetSize().depth) / 2; 218 var maxTurnAngle = turnLength * this.runSpeed / formationSize; 219 var currentAngle = cmpPosition.GetRotation().y; 220 var newSource = Vector2D.clone(this.path[this.pathIdx]); 221 var newTarget = Vector2D.clone(this.path[this.pathIdx - 1]); 222 var newDirection = Vector2D.clone(newTarget).sub(newSource); 223 var targetAngle = Math.atan2(newDirection.x, newDirection.y); 224 warn("new"); 225 warn(currentAngle); 226 warn(targetAngle); 227 228 // check where we need to turn to (between -Pi and Pi) 229 var posMod = function(a, n){ return a - Math.floor(a/n) * n; }; 230 var relativeTurn = posMod(targetAngle - currentAngle + Math.PI, 2 * Math.PI) - Math.PI; 231 // if we can't turn the full length, turn the maximum we can 232 warn(relativeTurn); 233 if (Math.abs(relativeTurn) > maxTurnAngle) 234 { 235 if (relativeTurn < 0) 236 cmpPosition.TurnTo(currentAngle - maxTurnAngle); 237 else 238 cmpPosition.TurnTo(currentAngle + maxTurnAngle); 239 return; 240 } 241 // we can take the full turn: finish the turn and continue in a straight line 242 cmpPosition.TurnTo(targetAngle); 243 this.state = "FOLLOW_LINE"; 244 var usedTime = Math.abs(relativeTurn) / maxTurnAngle * turnLength; 245 this.pathIdx--; 246 this.FollowLine(turnLength - usedTime); 247 }; 248 249 Engine.RegisterComponentType(IID_UnitMotion, "UnitMotionFormation", UnitMotionFormation); -
binaries/data/mods/public/simulation/templates/template_formation.xml
1 1 <?xml version="1.0" encoding="utf-8"?> 2 2 <Entity> 3 <!-- 3 <!----> 4 4 <VisualActor> 5 5 <Actor>props/special/common/waypoint_flag.xml</Actor> 6 <SilhouetteDisplay>false</SilhouetteDisplay> 7 <SilhouetteOccluder>true</SilhouetteOccluder> 8 <VisibleInAtlasOnly>false</VisibleInAtlasOnly> 6 9 </VisualActor> 7 -->10 <!----> 8 11 <Formation> 9 12 <RequiredMemberCount>1</RequiredMemberCount> 10 13 <DisabledTooltip></DisabledTooltip> … … 21 24 <FormationAttack> 22 25 <CanAttackAsFormation>false</CanAttackAsFormation> 23 26 </FormationAttack> 27 <Obstruction> 28 <Active>false</Active> 29 <BlockMovement>false</BlockMovement> 30 <BlockPathfinding>false</BlockPathfinding> 31 <BlockFoundation>false</BlockFoundation> 32 <BlockConstruction>false</BlockConstruction> 33 <DisableBlockMovement>true</DisableBlockMovement> 34 <DisableBlockPathfinding>true</DisableBlockPathfinding> 35 <Static width="30.0" depth="30.0"/> 36 </Obstruction> 24 37 <Ownership/> 25 38 <Position> 26 39 <Altitude>0</Altitude> … … 35 48 <FormationController>true</FormationController> 36 49 <CanGuard>true</CanGuard> 37 50 </UnitAI> 38 <UnitMotion> 39 <FormationController>true</FormationController> 40 <WalkSpeed>1.0</WalkSpeed> 41 <PassabilityClass>siege-large</PassabilityClass> 42 </UnitMotion> 51 <UnitMotionFormation/> 43 52 <Trader> 44 53 <GainMultiplier>1.0</GainMultiplier> 45 54 </Trader> -
binaries/data/mods/public/simulation/templates/template_unit.xml
37 37 <Identity> 38 38 <GenericName>Unit</GenericName> 39 39 <Classes datatype="tokens">Unit ConquestCritical</Classes> 40 <Formations datatype="tokens"> 41 formations/null 42 </Formations> 40 <Formations datatype="tokens"> 41 formations/null 42 formations/box 43 formations/column_closed 44 formations/line_closed 45 formations/column_open 46 formations/line_open 47 formations/flank 48 formations/battle_line 49 </Formations> 43 50 </Identity> 44 51 <Looter/> 45 52 <Minimap> -
source/scriptinterface/ScriptConversions.cpp
20 20 #include "ScriptInterface.h" 21 21 22 22 #include "graphics/Entity.h" 23 #include "simulation2/helpers/PathGoal.h" // to convert path goals 23 24 #include "ps/utf16string.h" 24 25 #include "ps/CLogger.h" 25 26 #include "ps/CStr.h" … … 205 206 JS::RootedValue position(cx); 206 207 JS::RootedValue rotation(cx); 207 208 208 // TODO: Report type errors 209 // TODO: Report type errors when loading attributes 209 210 if (!JS_GetProperty(cx, obj, "player", &player) || !FromJSVal(cx, player, out.playerID)) 210 211 FAIL("Failed to read Entity.player property"); 211 212 if (!JS_GetProperty(cx, obj, "templateName", &templateName) || !FromJSVal(cx, templateName, out.templateName)) … … 220 221 return true; 221 222 } 222 223 224 // TODO this doesn't work (probably always uses POINT) 225 template<> bool ScriptInterface::FromJSVal<PathGoal::Type>(JSContext* cx, JS::HandleValue v, PathGoal::Type& out) 226 { 227 std::string strVal; 228 ScriptInterface::FromJSVal(cx, v, static_cast<std::string&>(strVal)); 229 if (strVal == "CIRCLE") 230 out = PathGoal::CIRCLE; 231 if (strVal == "INVERTED_CIRCLE") 232 out = PathGoal::INVERTED_CIRCLE; 233 else if (strVal == "SQUARE") 234 out = PathGoal::SQUARE; 235 else if (strVal == "INVERTED_SQUARE") 236 out = PathGoal::INVERTED_SQUARE; 237 else 238 out = PathGoal::POINT; 239 return true; 240 } 241 242 template<> bool ScriptInterface::FromJSVal<PathGoal>(JSContext* cx, JS::HandleValue val, PathGoal& out) 243 { 244 JSAutoRequest rq(cx); 245 if (!val.isObject()) 246 FAIL("Argument must be an object"); 247 248 JS::RootedObject obj(cx, &val.toObject()); 249 JS::RootedValue type(cx); 250 JS::RootedValue x(cx); 251 JS::RootedValue z(cx); 252 JS::RootedValue u(cx); 253 JS::RootedValue v(cx); 254 JS::RootedValue hw(cx); 255 JS::RootedValue hh(cx); 256 257 258 // TODO: Report type errors 259 if (!JS_GetProperty(cx, obj, "type", &type) || !FromJSVal(cx, type, out.type)) 260 FAIL("Failed to read goal.type property"); 261 if (!JS_GetProperty(cx, obj, "x", &x) || !FromJSVal(cx, x, out.x)) 262 FAIL("Failed to read goal.x property"); 263 if (!JS_GetProperty(cx, obj, "z", &z) || !FromJSVal(cx, z, out.z)) 264 FAIL("Failed to read goal.z property"); 265 if (!JS_GetProperty(cx, obj, "u", &u) || !FromJSVal(cx, u, out.u)) 266 FAIL("Failed to read goal.u property"); 267 if (!JS_GetProperty(cx, obj, "v", &v) || !FromJSVal(cx, v, out.v)) 268 FAIL("Failed to read goal.v property"); 269 if (!JS_GetProperty(cx, obj, "hw", &hw) || !FromJSVal(cx, hw, out.hw)) 270 FAIL("Failed to read goal.hw property"); 271 if (!JS_GetProperty(cx, obj, "hh", &hh) || !FromJSVal(cx, hh, out.hh)) 272 FAIL("Failed to read goal.hh property"); 273 return true; 274 } 275 223 276 //////////////////////////////////////////////////////////////// 224 277 // Primitive types: 225 278 -
source/simulation2/components/CCmpObstruction.cpp
515 515 m_Clearance = clearance; 516 516 } 517 517 518 virtual void SetSize(entity_pos_t width, entity_pos_t height) 519 { 520 // require this to be inactive, so we don't have to force grid updates 521 ENSURE(m_Active == false); 522 m_Size0 = width; 523 m_Size0 = height; 524 } 525 518 526 virtual bool IsControlPersistent() 519 527 { 520 528 return m_ControlPersist; -
source/simulation2/components/CCmpPathfinder.cpp
184 184 } 185 185 186 186 187 pass_class_t CCmpPathfinder::GetPassabilityClass( const std::string&name)187 pass_class_t CCmpPathfinder::GetPassabilityClass(std::string name) 188 188 { 189 189 if (m_PassClassMasks.find(name) == m_PassClassMasks.end()) 190 190 { … … 610 610 611 611 // Async path requests: 612 612 613 u32 CCmpPathfinder::ComputePathAsync(entity_pos_t x0, entity_pos_t z0, const PathGoal&goal, pass_class_t passClass, entity_id_t notify)613 u32 CCmpPathfinder::ComputePathAsync(entity_pos_t x0, entity_pos_t z0, PathGoal goal, pass_class_t passClass, entity_id_t notify) 614 614 { 615 615 AsyncLongPathRequest req = { m_NextAsyncTicket++, x0, z0, goal, passClass, notify }; 616 616 m_AsyncLongPathRequests.push_back(req); … … 804 804 return ICmpObstruction::FOUNDATION_CHECK_SUCCESS; 805 805 } 806 806 807 u32 CCmpPathfinder::GetObstructedTiles(CFixedVector2D offset, entity_id_t id, pass_class_t passClass) 808 { 809 // Test against terrain: 810 ICmpObstructionManager::ObstructionSquare square; 811 CmpPtr<ICmpObstruction> cmpObstruction(GetSimContext(), id); 812 if (!cmpObstruction || !cmpObstruction->GetObstructionSquare(square)) 813 return 0; 814 815 square.x += offset.X; 816 square.z += offset.Y; 817 818 UpdateGrid(); 819 820 entity_pos_t expand; 821 const PathfinderPassability* passability = GetPassabilityFromMask(passClass); 822 if (passability && passability->m_HasClearance) 823 expand = passability->m_Clearance; 824 825 SimRasterize::Spans spans; 826 SimRasterize::RasterizeRectWithClearance(spans, square, expand, Pathfinding::NAVCELL_SIZE); 827 u32 obstructedTiles = 0; 828 for (SimRasterize::Span& span : spans) 829 { 830 i16 i0 = span.i0; 831 i16 i1 = span.i1; 832 i16 j = span.j; 833 834 // Fail if any span includes an impassable tile 835 for (i16 i = i0; i < i1; ++i) 836 if (i < 0 || i > m_Grid->m_W || j < 0 || j > m_Grid->m_H || !IS_PASSABLE(m_Grid->get(i, j), passClass)) 837 ++obstructedTiles; 838 } 839 840 return obstructedTiles; 841 } -
source/simulation2/components/CCmpPathfinder_Common.h
137 137 138 138 virtual void HandleMessage(const CMessage& msg, bool global); 139 139 140 virtual pass_class_t GetPassabilityClass( const std::string&name);140 virtual pass_class_t GetPassabilityClass(std::string name); 141 141 142 142 virtual std::map<std::string, pass_class_t> GetPassabilityClasses(); 143 143 … … 177 177 m_LongPathfinder.ComputePath(x0, z0, goal, passClass, ret); 178 178 } 179 179 180 virtual u32 ComputePathAsync(entity_pos_t x0, entity_pos_t z0, const PathGoal&goal, pass_class_t passClass, entity_id_t notify);180 virtual u32 ComputePathAsync(entity_pos_t x0, entity_pos_t z0, PathGoal goal, pass_class_t passClass, entity_id_t notify); 181 181 182 182 virtual void ComputeShortPath(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t r, entity_pos_t range, const PathGoal& goal, pass_class_t passClass, WaypointPath& ret); 183 183 … … 212 212 213 213 virtual ICmpObstruction::EFoundationCheck CheckBuildingPlacement(const IObstructionTestFilter& filter, entity_pos_t x, entity_pos_t z, entity_pos_t a, entity_pos_t w, entity_pos_t h, entity_id_t id, pass_class_t passClass, bool onlyCenterPoint); 214 214 215 virtual u32 GetObstructedTiles(CFixedVector2D offset, entity_id_t id, pass_class_t passClass); 216 215 217 virtual void FinishAsyncRequests(); 216 218 217 219 void ProcessLongRequests(const std::vector<AsyncLongPathRequest>& longRequests); -
source/simulation2/components/ICmpObstruction.cpp
47 47 48 48 BEGIN_INTERFACE_WRAPPER(Obstruction) 49 49 DEFINE_INTERFACE_METHOD_0("GetUnitRadius", entity_pos_t, ICmpObstruction, GetUnitRadius) 50 DEFINE_INTERFACE_METHOD_2("SetSize", void, ICmpObstruction, SetSize, entity_pos_t, entity_pos_t) 50 51 DEFINE_INTERFACE_METHOD_2("CheckFoundation", std::string, ICmpObstruction, CheckFoundation_wrapper, std::string, bool) 51 52 DEFINE_INTERFACE_METHOD_0("CheckDuplicateFoundation", bool, ICmpObstruction, CheckDuplicateFoundation) 52 53 DEFINE_INTERFACE_METHOD_2("GetEntityCollisions", std::vector<entity_id_t>, ICmpObstruction, GetEntityCollisions, bool, bool) -
source/simulation2/components/ICmpObstruction.h
54 54 55 55 virtual entity_pos_t GetSize() = 0; 56 56 57 /** 58 * Passively set the size of this obstruction 59 * This must only be used on inactive obstructions, as it won't update any grids 60 */ 61 virtual void SetSize(entity_pos_t width, entity_pos_t height) = 0; 62 57 63 virtual entity_pos_t GetUnitRadius() = 0; 58 64 59 65 virtual void SetUnitClearance(const entity_pos_t& clearance) = 0; -
source/simulation2/components/ICmpPathfinder.cpp
24 24 BEGIN_INTERFACE_WRAPPER(Pathfinder) 25 25 DEFINE_INTERFACE_METHOD_1("SetDebugOverlay", void, ICmpPathfinder, SetDebugOverlay, bool) 26 26 DEFINE_INTERFACE_METHOD_1("SetHierDebugOverlay", void, ICmpPathfinder, SetHierDebugOverlay, bool) 27 DEFINE_INTERFACE_METHOD_1("GetPassabilityClass", pass_class_t, ICmpPathfinder, GetPassabilityClass, std::string) 28 DEFINE_INTERFACE_METHOD_3("GetObstructedTiles", u32, ICmpPathfinder, GetObstructedTiles, CFixedVector2D, entity_id_t, pass_class_t) 29 DEFINE_INTERFACE_METHOD_5("ComputePathAsync", u32, ICmpPathfinder, ComputePathAsync, entity_pos_t, entity_pos_t, PathGoal, pass_class_t, entity_id_t) 27 30 END_INTERFACE_WRAPPER(Pathfinder) -
source/simulation2/components/ICmpPathfinder.h
59 59 * Get the tag for a given passability class name. 60 60 * Logs an error and returns something acceptable if the name is unrecognised. 61 61 */ 62 virtual pass_class_t GetPassabilityClass( const std::string&name) = 0;62 virtual pass_class_t GetPassabilityClass(std::string name) = 0; 63 63 64 64 virtual entity_pos_t GetClearance(pass_class_t passClass) const = 0; 65 65 … … 94 94 * Returns a unique non-zero number, which will match the 'ticket' in the result, 95 95 * so callers can recognise each individual request they make. 96 96 */ 97 virtual u32 ComputePathAsync(entity_pos_t x0, entity_pos_t z0, const PathGoal&goal, pass_class_t passClass, entity_id_t notify) = 0;97 virtual u32 ComputePathAsync(entity_pos_t x0, entity_pos_t z0, PathGoal goal, pass_class_t passClass, entity_id_t notify) = 0; 98 98 99 99 /** 100 100 * If the debug overlay is enabled, render the path that will computed by ComputePath. … … 150 150 */ 151 151 virtual ICmpObstruction::EFoundationCheck CheckBuildingPlacement(const IObstructionTestFilter& filter, entity_pos_t x, entity_pos_t z, entity_pos_t a, entity_pos_t w, entity_pos_t h, entity_id_t id, pass_class_t passClass, bool onlyCenterPoint) = 0; 152 152 153 /** 154 * Get the number of obstructed tiles that are under an obstruction of a 155 * certain entity. Allow an offset to easily test alternative positions. 156 */ 157 virtual u32 GetObstructedTiles(CFixedVector2D offset, entity_id_t id, pass_class_t passClass) = 0; 153 158 154 159 /** 155 160 * Toggle the storage and rendering of debug info. -
source/simulation2/scripting/EngineScriptConversions.cpp
27 27 #include "ps/Shapes.h" 28 28 #include "ps/utf16string.h" 29 29 #include "simulation2/helpers/Grid.h" 30 #include "simulation2/helpers/Pathfinding.h" 30 31 #include "simulation2/system/IComponent.h" 31 32 #include "simulation2/system/ParamNode.h" 32 33 … … 247 248 ret.setObject(*obj); 248 249 } 249 250 251 template<> void ScriptInterface::ToJSVal<Waypoint>(JSContext* cx, JS::MutableHandleValue ret, const Waypoint& val) 252 { 253 JSAutoRequest rq(cx); 254 255 // apply the Vector2D prototype to the return value 256 ScriptInterface::CxPrivate* pCxPrivate = ScriptInterface::GetScriptInterfaceAndCBData(cx); 257 JS::RootedObject proto(cx, &pCxPrivate->pScriptInterface->GetCachedValue(ScriptInterface::CACHE_VECTOR2DPROTO).toObject()); 258 JS::RootedObject obj(cx, JS_NewObject(cx, nullptr, proto, JS::NullPtr())); 259 if (!obj) 260 { 261 ret.setUndefined(); 262 return; 263 } 264 265 JS::RootedValue x(cx); 266 JS::RootedValue y(cx); 267 ToJSVal(cx, &x, val.x); 268 ToJSVal(cx, &y, val.z); 269 270 JS_SetProperty(cx, obj, "x", x); 271 JS_SetProperty(cx, obj, "y", y); 272 273 ret.setObject(*obj); 274 } 275 250 276 template<> void ScriptInterface::ToJSVal<Grid<u8> >(JSContext* cx, JS::MutableHandleValue ret, const Grid<u8>& val) 251 277 { 252 278 JSAutoRequest rq(cx); … … 309 335 } 310 336 ret.setObject(*obj); 311 337 } 338 339 template<> void ScriptInterface::ToJSVal<WaypointPath>(JSContext* cx, JS::MutableHandleValue ret, const WaypointPath& val) 340 { 341 JSAutoRequest rq(cx); 342 JS::RootedObject obj(cx, JS_NewArrayObject(cx, 0)); 343 if (!obj) 344 { 345 ret.setUndefined(); 346 return; 347 } 348 const std::vector<Waypoint>& waypointList = val.m_Waypoints; 349 for (size_t i = 0; i < waypointList.size(); ++i) 350 { 351 JS::RootedValue el(cx); 352 ScriptInterface::ToJSVal<Waypoint>(cx, &el, waypointList[i]); 353 JS_SetElement(cx, obj, i, el); 354 } 355 ret.setObject(*obj); 356 } -
source/simulation2/scripting/MessageTypeConversions.cpp
385 385 386 386 //////////////////////////////// 387 387 388 JS::Value CMessagePathResult::ToJSVal(ScriptInterface& UNUSED(scriptInterface)) const388 JS::Value CMessagePathResult::ToJSVal(ScriptInterface& scriptInterface) const 389 389 { 390 LOGWARNING("CMessagePathResult::ToJSVal not implemented"); 391 return JS::UndefinedValue(); 390 TOJSVAL_SETUP(); 391 SET_MSG_PROPERTY(ticket); 392 SET_MSG_PROPERTY(path); 393 return JS::ObjectValue(*obj); 392 394 } 393 395 394 396 CMessage* CMessagePathResult::FromJSVal(ScriptInterface& UNUSED(scriptInterface), JS::HandleValue UNUSED(val))