private void LateUpdate() { if (FSM == null) { return; } int currentMachineIndex = 0; while (currentMachineIndex < FSM.StackMachines.Length) { StackMachine machine = FSM.StackMachines[currentMachineIndex]; if (machine.Halted || (Step(machine) == StepResult.DoNextMachine)) { currentMachineIndex++; } } }
private void LogUnhandledEntity(string actionName, int entityIndex, FSMEntity entity, StackMachine machine) { Debug.LogWarning("FSM action '" + actionName + "' not implemented for entity " + entityIndex + " (" + entity.Value + ") @ " + (machine.IP - 1)); }
public int DoAction(string actionName, StackMachine machine, FSMRunner fsmRunner) { global::System.Collections.Generic.Queue <IntRef> args = machine.ArgumentQueue; switch (actionName) { case "null": // Do nothing? break; case "true": return(1); case "inc": { IntRef arg = args.Dequeue(); ++arg.Value; } break; case "dec": { IntRef arg = args.Dequeue(); --arg.Value; } break; case "set": { IntRef arg = args.Dequeue(); IntRef val = args.Dequeue(); arg.Value = val.Value; } break; case "isGreater": { IntRef val = args.Dequeue(); IntRef number = args.Dequeue(); bool greater = val.Value > number.Value; return(greater ? 1 : 0); } case "isLesser": { IntRef val = args.Dequeue(); IntRef number = args.Dequeue(); bool lesser = val.Value < number.Value; return(lesser ? 1 : 0); } case "isEqual": { IntRef val = args.Dequeue(); IntRef number = args.Dequeue(); bool equal = val.Value == number.Value; return(equal ? 1 : 0); } case "pushCam": CameraManager.Instance.PushCamera(); break; case "popCam": CameraManager.Instance.PopCamera(); break; case "timeGreater": IntRef timerNo = args.Dequeue(); IntRef seconds = args.Dequeue(); float secondsElapsed = Time.unscaledTime - fsmRunner.Timers[timerNo.Value]; return(secondsElapsed >= seconds.Value ? 1 : 0); case "isKeypress": return(Input.GetKeyDown(KeyCode.Space) ? 1 : 0); case "camObjDir": { if (CameraManager.Instance.IsMainCameraActive) { break; } var camera = CameraManager.Instance.ActiveCamera; IntRef whichEntity = args.Dequeue(); FSMEntity origoEntity = fsmRunner.FSM.EntityTable[whichEntity.Value]; GameObject entity = origoEntity.Object; Vector3 relativePos = new Vector3(args.Dequeue().Value, args.Dequeue().Value, args.Dequeue().Value) / 100.0f; int yaw = args.Dequeue().Value; int roll = args.Dequeue().Value; int pitch = args.Dequeue().Value; Vector3 rotation = new Vector3(yaw, pitch, roll) / 100.0f; Vector3 newPos = entity.transform.position + (entity.transform.rotation * relativePos); if (newPos.y < entity.transform.position.y + 1) { newPos.y = entity.transform.position.y + 1; } camera.transform.position = newPos; camera.transform.rotation = entity.transform.rotation * Quaternion.Euler(rotation); } break; case "camPosObj": { if (CameraManager.Instance.IsMainCameraActive) { break; } var camera = CameraManager.Instance.ActiveCamera; int pathIndex = args.Dequeue().Value; int height = args.Dequeue().Value; int watchTarget = args.Dequeue().Value; FSMPath path = fsmRunner.FSM.Paths[pathIndex]; Vector3 nodePos = path.GetWorldPosition(0); nodePos.y = Utils.GroundHeightAtPoint(nodePos.x, nodePos.z) + height * 0.01f; camera.transform.position = nodePos; GameObject entity = fsmRunner.FSM.EntityTable[watchTarget].Object; camera.transform.LookAt(entity.transform, Vector3.up); } break; case "camObjObj": { if (CameraManager.Instance.IsMainCameraActive) { break; } int objectIndex = args.Dequeue().Value; float xPos = args.Dequeue().Value; float yPos = args.Dequeue().Value; float zPos = args.Dequeue().Value; int watchTarget = args.Dequeue().Value; FSMEntity anchorEntity = fsmRunner.FSM.EntityTable[objectIndex]; FSMEntity targetEntity = fsmRunner.FSM.EntityTable[watchTarget]; var camera = CameraManager.Instance.ActiveCamera; camera.transform.SetParent(anchorEntity.Object.transform); camera.transform.localPosition = new Vector3(xPos * 0.01f, zPos * 0.01f, yPos * 0.01f); camera.transform.LookAt(targetEntity.Object.transform, Vector3.up); } break; case "camTransObj": { if (CameraManager.Instance.IsMainCameraActive) { break; } var camera = CameraManager.Instance.ActiveCamera; int pathIndex = args.Dequeue().Value; int targetSpeed = args.Dequeue().Value; float height = args.Dequeue().Value * 0.01f; FSMPath path = fsmRunner.FSM.Paths[pathIndex]; if (args.Count == 0) { Vector3 nodePos = path.GetWorldPosition(0); nodePos.y = Utils.GroundHeightAtPoint(nodePos.x, nodePos.z) + height; camera.transform.position = nodePos; break; } int watchTarget = args.Dequeue().Value; GameObject entity = fsmRunner.FSM.EntityTable[watchTarget].Object; camera.transform.LookAt(entity.transform, Vector3.up); camera.SetTargetPath(path, targetSpeed, height); } break; case "camIsArrived": { if (CameraManager.Instance.IsMainCameraActive) { break; } var camera = CameraManager.Instance.ActiveCamera; if (camera.Arrived) { camera.Arrived = false; return(1); } return(0); } case "goto": { int entityIndex = args.Dequeue().Value; int pathIndex = args.Dequeue().Value; int targetSpeed = args.Dequeue().Value; FSMEntity entity = fsmRunner.FSM.EntityTable[entityIndex]; FSMPath path = fsmRunner.FSM.Paths[pathIndex]; Car car = entity.Object.GetComponent <Car>(); if (car != null) { car.SetTargetPath(path, targetSpeed); break; } LogUnhandledEntity(actionName, entityIndex, entity, machine); } break; case "isWithinNav": { int pathIndex = args.Dequeue().Value; int entityIndex = args.Dequeue().Value; int distance = args.Dequeue().Value; FSMPath path = fsmRunner.FSM.Paths[pathIndex]; FSMEntity entity = fsmRunner.FSM.EntityTable[entityIndex]; Car car = entity.Object.GetComponent <Car>(); if (car != null) { bool within = car.IsWithinNav(path, distance); return(within ? 1 : 0); } LogUnhandledEntity(actionName, entityIndex, entity, machine); } break; case "isWithinSqNav": { int pathIndex = args.Dequeue().Value; int entityIndex = args.Dequeue().Value; int distance = args.Dequeue().Value; FSMPath path = fsmRunner.FSM.Paths[pathIndex]; FSMEntity entity = fsmRunner.FSM.EntityTable[entityIndex]; Car car = entity.Object.GetComponent <Car>(); if (car != null) { bool within = car.IsWithinNav(path, (int)Mathf.Sqrt(distance)); return(within ? 1 : 0); } LogUnhandledEntity(actionName, entityIndex, entity, machine); } break; case "follow": { int entityIndex = args.Dequeue().Value; int targetIndex = args.Dequeue().Value; int unk1 = args.Dequeue().Value; int unk2 = args.Dequeue().Value; int xOffset = args.Dequeue().Value; int targetSpeed = args.Dequeue().Value; FSMEntity entity = fsmRunner.FSM.EntityTable[entityIndex]; FSMEntity targetEntity = fsmRunner.FSM.EntityTable[targetIndex]; Car car = entity.Object.GetComponent <Car>(); Car targetCar = targetEntity.Object.GetComponent <Car>(); if (car != null && targetCar != null) { car.SetFollowTarget(targetCar, xOffset, targetSpeed); break; } LogUnhandledEntity(actionName, entityIndex, entity, machine); } break; case "isAtFollow": { int entityIndex = args.Dequeue().Value; FSMEntity entity = fsmRunner.FSM.EntityTable[entityIndex]; Car car = entity.Object.GetComponent <Car>(); if (car != null) { bool atFollow = car.AtFollowTarget(); return(atFollow ? 1 : 0); } LogUnhandledEntity(actionName, entityIndex, entity, machine); } break; case "teleport": { int entityIndex = args.Dequeue().Value; int pathIndex = args.Dequeue().Value; int targetSpeed = args.Dequeue().Value; int height = args.Dequeue().Value; FSMPath path = fsmRunner.FSM.Paths[pathIndex]; FSMEntity entity = fsmRunner.FSM.EntityTable[entityIndex]; Vector3 nodePos = path.GetWorldPosition(0); nodePos.y = Utils.GroundHeightAtPoint(nodePos.x, nodePos.z) + height * 0.01f; entity.Object.transform.position = nodePos; Car car = entity.Object.GetComponent <Car>(); if (car != null) { car.SetSpeed(targetSpeed); car.SetTargetPath(path, targetSpeed); break; } LogUnhandledEntity(actionName, entityIndex, entity, machine); } break; case "teleportOffset": { int entityIndex = args.Dequeue().Value; int pathIndex = args.Dequeue().Value; int targetSpeed = args.Dequeue().Value; int height = args.Dequeue().Value; var offsetX = args.Dequeue().Value; var offsetZ = args.Dequeue().Value; FSMPath path = fsmRunner.FSM.Paths[pathIndex]; FSMEntity entity = fsmRunner.FSM.EntityTable[entityIndex]; Vector3 nodePos = path.GetWorldPosition(0) + new Vector3(offsetX, 0, offsetZ); nodePos.y = Utils.GroundHeightAtPoint(nodePos.x, nodePos.z) + height * 0.01f; entity.Object.transform.position = nodePos; Car car = entity.Object.GetComponent <Car>(); if (car != null) { car.SetSpeed(targetSpeed); car.SetTargetPath(path, targetSpeed); break; } LogUnhandledEntity(actionName, entityIndex, entity, machine); } break; case "isArrived": { int entityIndex = args.Dequeue().Value; FSMEntity origoEntity = fsmRunner.FSM.EntityTable[entityIndex]; GameObject entity = origoEntity.Object; Car car = entity.GetComponent <Car>(); if (car != null) { if (car.Arrived) { car.Arrived = false; return(1); } return(0); } LogUnhandledEntity(actionName, entityIndex, origoEntity, machine); } break; case "sit": { int entityIndex = args.Dequeue().Value; FSMEntity entity = fsmRunner.FSM.EntityTable[entityIndex]; Car car = entity.Object.GetComponent <Car>(); if (car != null) { car.Sit(); break; } LogUnhandledEntity(actionName, entityIndex, entity, machine); } break; case "setAvoid": { int entityIndex = args.Dequeue().Value; int avoidIndex = args.Dequeue().Value; FSMEntity entity = fsmRunner.FSM.EntityTable[entityIndex]; FSMEntity avoidEntity = fsmRunner.FSM.EntityTable[avoidIndex]; Car car = entity.Object.GetComponent <Car>(); WorldEntity target = avoidEntity.WorldEntity; if (car != null && target != null) { // TODO: Figure out 'avoid' logic - don't path near object? break; } LogUnhandledEntity(actionName, entityIndex, entity, machine); } break; case "setMaxAttackers": { int entityIndex = args.Dequeue().Value; int maxAttackers = args.Dequeue().Value; FSMEntity entity = fsmRunner.FSM.EntityTable[entityIndex]; if (entity.WorldEntity != null) { entity.WorldEntity.MaxAttackers = maxAttackers; break; } LogUnhandledEntity(actionName, entityIndex, entity, machine); } break; case "setSkill": { int entityIndex = args.Dequeue().Value; int skill1 = args.Dequeue().Value; int skill2 = args.Dequeue().Value; FSMEntity entity = fsmRunner.FSM.EntityTable[entityIndex]; Car car = entity.Object.GetComponent <Car>(); if (car != null) { car.Skill1 = skill1; car.Skill2 = skill2; return(0); } LogUnhandledEntity(actionName, entityIndex, entity, machine); } break; case "setAgg": { int entityIndex = args.Dequeue().Value; int aggressionValue = args.Dequeue().Value; FSMEntity entity = fsmRunner.FSM.EntityTable[entityIndex]; Car car = entity.Object.GetComponent <Car>(); if (car != null) { car.Aggressiveness = aggressionValue; return(0); } LogUnhandledEntity(actionName, entityIndex, entity, machine); } break; case "isAttacked": { int entityIndex = args.Dequeue().Value; FSMEntity entity = fsmRunner.FSM.EntityTable[entityIndex]; Car car = entity.Object.GetComponent <Car>(); if (car != null) { return(car.Attacked ? 1 : 0); } LogUnhandledEntity(actionName, entityIndex, entity, machine); } break; case "isDead": { int entityIndex = args.Dequeue().Value; FSMEntity entity = fsmRunner.FSM.EntityTable[entityIndex]; if (entity.WorldEntity != null) { return(entity.WorldEntity.Alive ? 0 : 1); } LogUnhandledEntity(actionName, entityIndex, entity, machine); } break; case "isWithin": { int entityIndex = args.Dequeue().Value; int targetIndex = args.Dequeue().Value; int distance = args.Dequeue().Value; FSMEntity entity = fsmRunner.FSM.EntityTable[entityIndex]; FSMEntity target = fsmRunner.FSM.EntityTable[targetIndex]; bool within = Vector3.Distance(entity.Object.transform.position, target.Object.transform.position) < distance; return(within ? 1 : 0); } case "cbFromPrior": { int soundId = args.Dequeue().Value; int owner = args.Dequeue().Value; int queueFlag = args.Dequeue().Value; QueueRadio(fsmRunner, soundId, queueFlag, owner); } break; case "cbPrior": { int soundId = args.Dequeue().Value; int queueFlag = args.Dequeue().Value; QueueRadio(fsmRunner, soundId, queueFlag, -1); } break; case "rand": { IntRef arg = args.Dequeue(); IntRef val = args.Dequeue(); arg.Value = Random.Range(0, val.Value); } break; case "stopCB": RadioManager.Instance.Stop(); break; case "isCBEmpty": { return(RadioManager.Instance.IsQueueEmpty() ? 1 : 0); } case "startTimer": int timerIndex = args.Dequeue().Value; fsmRunner.Timers[timerIndex] = Time.unscaledTime; break; default: Debug.LogWarning("FSM action not implemented: " + actionName + " @ " + (machine.IP - 1)); break; } return(0); }
private StepResult Step(StackMachine machine) { ByteCode byteCode = FSM.ByteCode[machine.IP++]; switch (byteCode.OpCode) { case OpCode.PUSH: machine.Stack.Push(new IntRef(byteCode.Value)); break; case OpCode.ARGPUSH_S: IntRef sVal = machine.Stack[byteCode.Value - 1]; machine.ArgumentQueue.Enqueue(sVal); break; case OpCode.ARGPUSH_B: int idx = machine.Constants.Length + (byteCode.Value + 1); IntRef bVal = machine.Constants[idx]; machine.ArgumentQueue.Enqueue(bVal); break; case OpCode.ADJUST: int addToSP = byteCode.Value; if (addToSP < 1) { throw new NotImplementedException("What to do when adjusting 0 or negative values?"); } for (int i = 0; i < addToSP; i++) { machine.Stack.Push(new IntRef(0)); } break; case OpCode.DROP: int subFromSP = byteCode.Value; if (subFromSP < 0) { throw new NotImplementedException("Expecting positive values"); } for (int i = 0; i < subFromSP; i++) { machine.Stack.Pop(); } break; case OpCode.JMP: machine.IP = (uint)byteCode.Value; break; case OpCode.JZ: if (machine.ResultReg == 0) { machine.IP = (uint)byteCode.Value; } break; case OpCode.JMP_I: machine.IP = (uint)byteCode.Value; return(StepResult.DoNextMachine); case OpCode.RST: machine.Halted = true; return(StepResult.DoNextMachine); case OpCode.ACTION: string actionName = FSM.ActionTable[byteCode.Value]; machine.ResultReg = _actionDelegator.DoAction(actionName, machine, this); machine.ArgumentQueue.Clear(); break; case OpCode.NEG: if (machine.ResultReg == 1) { machine.ResultReg = 0; } else { machine.ResultReg = 1; } break; default: throw new NotImplementedException("Unimplemented bytecode " + byteCode.OpCode); } return(StepResult.NotDone); }