//a method to trigger the escape on attack behavior public void Trigger() { if (isActive == false) //do not proceed if the component is not active { return; } Vector3 targetPosition = gameMgr.MvtMgr.GetRandomMovablePosition(transform.position, range.getRandomValue(), unit, unit.MovementComp.GetAgentAreaMask()); //find a random position to escape to if (GameManager.MultiplayerGame == false) //single player game { TriggerLocal(targetPosition); } else if (RTSHelper.IsLocalPlayer(unit) == true) //multiplayer game and this is the local player { NetworkInput newInput = new NetworkInput() //create new input for the escape task { sourceMode = (byte)InputMode.unit, targetMode = (byte)InputMode.unitEscape, initialPosition = transform.position, targetPosition = targetPosition }; InputManager.SendInput(newInput, unit, null); //send input to input manager } }
//enable an attack entity public ErrorMessage EnableAttack(int ID) { //if the attack type is locked then it can't be activated if (AttackEntities[ID].IsLocked) { return(ErrorMessage.attackTypeLocked); } else if (AttackEntities[ID].CoolDownActive == true) //if the target attack type is in cool down right now: { return(ErrorMessage.attackInCooldown); } if (GameManager.MultiplayerGame == false) //single player game -> directly enable attack entity { EnableAttackLocal(ID); } else if (RTSHelper.IsLocalPlayer(activeAttack.FactionEntity)) { NetworkInput newInput = new NetworkInput() { sourceMode = (byte)InputMode.factionEntity, targetMode = (byte)InputMode.multipleAttack, value = ID }; InputManager.SendInput(newInput, factionEntity, null); //send input to input manager } return(ErrorMessage.none); }
//a method that launches the attack movement of a list of units public void LaunchAttack(List <Unit> units, FactionEntity targetEntity, Vector3 targetPosition, AttackModes attackMode, bool playerCommand) { if (units.Count == 1) //one unit only? { //use the one-unit attack movement LaunchAttack(units[0], targetEntity, targetPosition, attackMode, playerCommand); return; } if (GameManager.MultiplayerGame == false) //single player game, directly prepare the unit's attack movement { PrepareMove(units, targetPosition, targetEntity ? targetEntity.GetRadius() : 0.0f, targetEntity, InputMode.attack, playerCommand, true, attackMode, targetEntity); } else if (RTSHelper.IsLocalPlayer(units[0]) == true) //multiplayer game and this is the local player { //send input action to the input manager NetworkInput newInput = new NetworkInput() { sourceMode = (byte)InputMode.unitGroup, targetMode = (byte)InputMode.attack, targetPosition = targetPosition, value = (int)attackMode, groupSourceID = InputManager.UnitListToString(units) }; //sent input InputManager.SendInput(newInput, null, targetEntity); } }
public void OnTimeOutUpdate() //updating the client in case of a time out { if (Disconnected == true || TimingOut == false) //if the client is either already disconnected or not in a time out { return; //do not continue } kickTimer -= NetworkFactionManager_Mirror.DeltaTime; //keep the kicking timer going if (kickTimer <= 0.0f) //if the timer is over, then the player will be kicked { if (gameMgr.GetFaction(FactionID).FactionManager_Mirror) //if there's a network faction manager still { gameMgr.GetFaction(FactionID).FactionManager_Mirror.connectionToClient.Disconnect(); //disconnect it } else //no network faction manager? { //inform other players that this client has left: NetworkInput newInput = new NetworkInput() { sourceMode = (byte)InputMode.destroy, targetMode = (byte)InputMode.faction, value = FactionID }; InputManager.SendInput(newInput, null, null); //send the input to destroy this faction } Disconnected = true; } }
//this is the only way to communicate between objects in the scene and multiplayer faction managers. public static void SendInput(NetworkInput newInput, Entity source, Entity target) { if (source) //if there's a source object { if (newInput.sourceMode == (byte)InputMode.create) //if we're creating an object, then look in the spawnable prefabs list { newInput.sourceID = InputManager.instance.spawnablePrefabs.IndexOf(source); //get the index of the prefab from the spawnable prefabs list as the source ID } else //for the rest of input source modes, get the ID from the spawned objects list { newInput.sourceID = source.MultiplayerKey; } } else { newInput.sourceID = -1; //no source object } if (target) //if there's a valid target object { newInput.targetID = target.MultiplayerKey; //get its index from the spawn objects and set it as the target ID. } else { newInput.targetID = -1; //no target object assigned } newInput.factionID = GameManager.PlayerFactionID; //source of the input is the local player's faction #if RTSENGINE_MIRROR if (FactionManager_Mirror != null) //network faction manager hasn't been assigned yet { FactionManager_Mirror.CmdSendInput(newInput); //send the input } #endif }
//execute a command that destroys a faction entity or a whole faction private void OnDestroyCommand(NetworkInput command) { switch ((InputMode)command.targetMode) { case InputMode.factionEntity: //destroying a unit (spawnedObjects[command.sourceID] as FactionEntity).EntityHealthComp.DestroyFactionEntityLocal(command.value == 1 ? true : false); break; case InputMode.resource: //destroy a resource and providing the last resource collector as a parameter (if it exists). (spawnedObjects[command.sourceID] as Resource).DestroyResourceLocal(command.targetID >= 0 ? spawnedObjects[command.targetID] as Unit : null); break; case InputMode.faction: gameMgr.OnFactionDefeatedLocal(command.value); //the command.value holds the faction ID of the faction to destroy if (GameManager.PlayerFactionID == GameManager.HostFactionID) //if this is the host { #if RTSENGINE_MIRROR FactionManager_Mirror.OnFactionDefeated(command.value); //to mark the defeated player as disconnected. #endif } break; default: Debug.LogError("[Input Manager] Invalid input target mode for destroy command."); break; } }
//the Move method is called when another component requests the movement of a list of units public void Move(List <Unit> units, Vector3 destination, float offsetRadius, Entity target, InputMode targetMode, bool playerCommand) { if (units.Count == 1) //if there's only one unit in the list { Move(units[0], destination, offsetRadius, target, targetMode, playerCommand); //use the one-unit movement return; } if (GameManager.MultiplayerGame == false) //single player game, directly prepare the unit's list movement { PrepareMove(units, destination, offsetRadius, target, targetMode, playerCommand); } else if (RTSHelper.IsLocalPlayer(units[0]) == true) //multiplayer game and this is the local player { //send input action to the input manager NetworkInput newInput = new NetworkInput() { sourceMode = (byte)InputMode.unitGroup, targetMode = (byte)targetMode, targetPosition = destination, value = Mathf.FloorToInt(offsetRadius), groupSourceID = InputManager.UnitListToString(units) }; //sent input InputManager.SendInput(newInput, null, target); } }
//execute a resource related command: private void OnResourceCommand(NetworkInput command) { Resource sourceResource = spawnedObjects[command.sourceID] as Resource; //get the source resource if (spawnedObjects.TryGetValue(command.targetID, out Entity target)) //only if there's a target entity { switch ((InputMode)command.targetMode) { case InputMode.health: //adding/removing an amount from the resource sourceResource.AddAmountLocal(command.value, target as Unit); break; } } }
//execute a building related command: private void OnBuildingCommand(NetworkInput command) { Building sourceBuilding = spawnedObjects[command.sourceID] as Building; //get the source building Entity target = null; //get the target obj spawnedObjects.TryGetValue(command.targetID, out target); switch ((InputMode)command.targetMode) { case InputMode.attack: //attacking a target sourceBuilding.AttackComp.SetTargetLocal(target ? target as FactionEntity : null, command.targetPosition); break; } }
//a method called when the resource object is to be destroyed public void DestroyResource(Unit source) { if (GameManager.MultiplayerGame == false) //if this is a single player game -> go ahead directly { DestroyResourceLocal(source); } else if (RTSHelper.IsLocalPlayer(source)) //multiplayer game and the resource collector belongs to the local faction { NetworkInput newInput = new NetworkInput() { sourceMode = (byte)InputMode.destroy, targetMode = (byte)InputMode.resource, }; InputManager.SendInput(newInput, this, source); } }
//add/remove to/from the resource public void AddAmount(int value, Unit source) { if (GameManager.MultiplayerGame == false) //if this is a single player game -> go ahead directly { AddAmountLocal(value, source); } else if (RTSHelper.IsLocalPlayer(source)) //multiplayer game and the resource collector belongs to the local faction { NetworkInput newInput = new NetworkInput() { sourceMode = (byte)InputMode.resource, targetMode = (byte)InputMode.health, value = value }; InputManager.SendInput(newInput, this, source); } }
//execute a unit group movement command public void OnUnitGroupMovementCommand(NetworkInput command) { List <Unit> unitList = StringToUnitList(command.groupSourceID); //get the units list if (unitList.Count > 0) //if there's actual units in the list { if (command.targetMode == (byte)InputMode.attack) //if the target mode is attack -> make the unit group launch an attack on the target. { FactionEntity targetEntity = spawnedObjects[command.targetID] as FactionEntity; //get the faction entity component of the target object gameMgr.MvtMgr.PrepareMove(unitList, command.targetPosition, targetEntity.GetRadius(), targetEntity, InputMode.attack, false, true, (MovementManager.AttackModes)command.value, targetEntity); } else //target movement type can be none, portal, APC, etc... { gameMgr.MvtMgr.PrepareMove(unitList, command.targetPosition, command.value, null, (InputMode)command.targetMode, true); } } }
//a method called to execute commands (collected inputs) sent by the host/server public void LaunchCommand(NetworkInput command) { switch ((InputMode)command.sourceMode) { case InputMode.create: OnCreateCommand(command); break; case InputMode.destroy: OnDestroyCommand(command); break; case InputMode.factionEntity: OnFactionEntityCommand(command); break; case InputMode.unitGroup: OnUnitGroupMovementCommand(command); break; case InputMode.unit: OnUnitCommand(command); break; case InputMode.building: OnBuildingCommand(command); break; case InputMode.resource: OnResourceCommand(command); break; case InputMode.APC: OnAPCCommand(command); break; case InputMode.customCommand: CustomEvents.OnCustomCommand(command); break; default: Debug.LogError("[Input Manager] Invalid input source mode!"); break; } }
//Game state methods: //called when a faction is defeated public void OnFactionDefeated(int factionID) { if (MultiplayerGame == false) //in the case of a singleplayer game { OnFactionDefeatedLocal(factionID); //directly mark the faction as defeated } else //multiplayer game: { NetworkInput NewInputAction = new NetworkInput() //ask the server to announce that the faction has been defeated. { sourceMode = (byte)InputMode.destroy, targetMode = (byte)InputMode.faction, value = factionID, }; InputManager.SendInput(NewInputAction, null, null); //send input action to the input manager } }
//execute a APC related command: private void OnAPCCommand(NetworkInput command) { APC sourceAPC = (spawnedObjects[command.sourceID] as FactionEntity).APCComp; //get the source resource switch ((InputMode)command.targetMode) { case InputMode.APCEjectAll: //ejecting all units from the APC sourceAPC.EjectAllLocal(command.value == 1); break; case InputMode.APCEject: Unit targetUnit = (command.targetID >= 0 && command.targetID < spawnedObjects.Count) ? spawnedObjects[command.targetID] as Unit : null; //get the target unit sourceAPC.EjectLocal(targetUnit, command.value == 1); break; } }
//a method that sends the unit to drop off resources at the drop off building public void SendToDropOff() { if (GameManager.MultiplayerGame == false) //if this is a singleplayer game then go ahead directly { SendToDropOffLocal(); } else if (RTSHelper.IsLocalPlayer(unit)) //multiplayer game and this is the collector's owner { NetworkInput newInput = new NetworkInput() { sourceMode = (byte)InputMode.unit, targetMode = (byte)InputMode.dropoff, initialPosition = transform.position }; InputManager.SendInput(newInput, unit, dropOffBuilding); } }
//a method called to eject all units public void EjectAll(bool destroyed) { if (GameManager.MultiplayerGame == false) //if this is a singleplayer game then go ahead directly { EjectAllLocal(destroyed); } else if (RTSHelper.IsLocalPlayer(FactionEntity)) //multiplayer game and this is the APC's owner { NetworkInput newInput = new NetworkInput() { sourceMode = (byte)InputMode.APC, targetMode = (byte)InputMode.APCEjectAll, value = destroyed == true ? 1 : 0 }; InputManager.SendInput(newInput, FactionEntity, null); //send input to input manager } }
//called when the building picks a target public override void SetTarget(FactionEntity newTarget, Vector3 newTargetPosition) { if (GameManager.MultiplayerGame == false) //single player game, go ahead { SetTargetLocal(newTarget, newTargetPosition); } else if (RTSHelper.IsLocalPlayer(building) == true) //only if this is a local player { NetworkInput newInput = new NetworkInput() { sourceMode = (byte)InputMode.building, targetMode = (byte)InputMode.attack, targetPosition = newTargetPosition, }; InputManager.SendInput(newInput, building, newTarget); //send input return; } }
//execute a command that creates a faction entity (unit/building): private void OnCreateCommand(NetworkInput command) { Entity prefab = spawnablePrefabs[command.sourceID]; //the prefab to spawn. switch ((InputMode)command.targetMode) { case InputMode.unit: Entity creator = null; //get the creator building spawnedObjects.TryGetValue(command.targetID, out creator); gameMgr.UnitMgr.CreateUnitLocal(prefab as Unit, command.initialPosition, prefab.transform.rotation, command.targetPosition, command.factionID, (creator as Building), command.value == 0, command.value == 2); break; case InputMode.building: /* * 0 -> PlacedByDefault = false & Capital = false * 1 -> PlacedByDefault = true & Capital = false * 2 -> PlacedByDefault = false & Capital = true * 3 -> PlacedByDefault = true & Capital = true * */ //determine whether the building will be placed by default or if it's a capital building. bool placedByDefault = (command.value == 1 || command.value == 3) ? true : false; bool isCapital = (command.value == 2 || command.value == 3) ? true : false; Entity center = null; //get the building's center border component spawnedObjects.TryGetValue(command.targetID, out center); gameMgr.BuildingMgr.CreatePlacedInstanceLocal(prefab as Building, command.initialPosition, command.targetPosition.y, (center as Building)?.BorderComp, command.factionID, placedByDefault, isCapital); break; case InputMode.resource: gameMgr.ResourceMgr.CreateResourceLocal(prefab as Resource, command.initialPosition); break; default: Debug.LogError("[Input Manager] Invalid input target mode for creation command."); break; } }
//creates an instance of a building that is instantly placed: public void CreatePlacedInstance(Building buildingPrefab, Vector3 placementPosition, float yEulerAngle, Border buildingCenter, int factionID, bool placedByDefault = false, bool factionCapital = false) { if (GameManager.MultiplayerGame == false) { //if it's a single player game. CreatePlacedInstanceLocal(buildingPrefab, placementPosition, yEulerAngle, buildingCenter, factionID, placedByDefault, factionCapital); //place the building } else { //in case it's a multiplayer game: //ask the server to spawn the building for all clients: NetworkInput newInput = new NetworkInput() { sourceMode = (byte)InputMode.create, targetMode = (byte)InputMode.building, value = (placedByDefault && factionCapital) ? 3 : (placedByDefault ? 1 : (factionCapital ? 2 : 0)), initialPosition = placementPosition, targetPosition = new Vector3(0.0f, yEulerAngle, 0.0f) }; InputManager.SendInput(newInput, buildingPrefab, buildingCenter?.building); //send input to input manager } }
//execute a unit related command public void OnFactionEntityCommand(NetworkInput command) { FactionEntity sourceFactionEntity = spawnedObjects[command.sourceID] as FactionEntity; //get the source faction entity Entity target = null; //get the target obj spawnedObjects.TryGetValue(command.targetID, out target); switch ((InputMode)command.targetMode) { case InputMode.health: //adding health sourceFactionEntity.EntityHealthComp.AddHealthLocal(command.value, (target == null) ? null : target as FactionEntity); break; case InputMode.multipleAttack: //switching attack types. sourceFactionEntity.MultipleAttackMgr.EnableAttack(command.value); break; } }
//a method called to destroy the faction entity: public void DestroyFactionEntity(bool upgrade) { if (GameManager.MultiplayerGame == false) //if it's a single player game { DestroyFactionEntityLocal(upgrade); //destroy faction entity directly } else //multiplayer game { if (RTSHelper.IsLocalPlayer(factionEntity)) //make sure that it's this faction entity belongs to the local player { //send input action to the input manager NetworkInput NewInputAction = new NetworkInput { sourceMode = (byte)InputMode.destroy, targetMode = (byte)InputMode.factionEntity, value = (upgrade == true) ? 1 : 0 //when upgrade == true, then set to 1. if not set to 0 }; InputManager.SendInput(NewInputAction, factionEntity, null); //send to input manager } } }
//called when the unit attempts to set a new target public virtual ErrorMessage SetTarget(E newTarget, InputMode targetMode = InputMode.none) { if (GameManager.MultiplayerGame == false) //if this is a singleplayer game then go ahead directly { SetTargetLocal(newTarget); } else if (RTSHelper.IsLocalPlayer(unit)) //multiplayer game and this is the unit's owner { NetworkInput newInput = new NetworkInput() { sourceMode = (byte)InputMode.unit, targetMode = (byte)targetMode, initialPosition = transform.position, targetPosition = newTarget.transform.position }; InputManager.SendInput(newInput, unit, newTarget); } return(ErrorMessage.none); }
//add/remove health to the faction entity's: public void AddHealth(int value, FactionEntity source) { if (GameManager.MultiplayerGame == false) //if it's a single player game { AddHealthLocal(value, source); //add the health directly } else //multiplayer game { if (RTSHelper.IsLocalPlayer(factionEntity)) //make sure that it's this faction entity belongs to the local player { //crete new input NetworkInput newInput = new NetworkInput { sourceMode = (byte)InputMode.factionEntity, targetMode = (byte)InputMode.health, value = value }; //send the input to the input manager InputManager.SendInput(newInput, factionEntity, source); } } }
//the Move method is called when another component requests the movement of a single unit public void Move(Unit unit, Vector3 destination, float offsetRadius, Entity target, InputMode targetMode, bool playerCommand) { if (GameManager.MultiplayerGame == false) //single player game, directly prepare the unit's movement { PrepareMove(unit, destination, offsetRadius, target, targetMode, playerCommand); } else if (RTSHelper.IsLocalPlayer(unit)) //multiplayer game and this is the local player { //send input action to the input manager NetworkInput newInput = new NetworkInput() { sourceMode = (byte)InputMode.unit, targetMode = (byte)targetMode, initialPosition = unit.transform.position, targetPosition = destination, value = Mathf.FloorToInt(offsetRadius) }; //sent input InputManager.SendInput(newInput, unit, target); } }
//a method that spawns a resource instance: public void CreateResource(Resource resourcePrefab, Vector3 spawnPosition) { if (resourcePrefab == null) //invalid prefab { return; } if (GameManager.MultiplayerGame == false) //single player game: { CreateResourceLocal(resourcePrefab, spawnPosition); } else { NetworkInput newInput = new NetworkInput() { sourceMode = (byte)InputMode.create, targetMode = (byte)InputMode.resource, initialPosition = spawnPosition }; InputManager.SendInput(newInput, resourcePrefab, null); } }
//a method called to eject one unit public void Eject(Unit unit, bool destroyed) { if (unit == null || storedUnits.Contains(unit) == false) //invalid unit or unit that's not stored here? { return; } if (GameManager.MultiplayerGame == false) //if this is a singleplayer game then go ahead directly { EjectLocal(unit, destroyed); } else if (RTSHelper.IsLocalPlayer(FactionEntity)) //multiplayer game and this is the APC's owner { NetworkInput newInput = new NetworkInput() { sourceMode = (byte)InputMode.APC, targetMode = (byte)InputMode.APCEject, value = destroyed == true ? 1 : 0 }; InputManager.SendInput(newInput, FactionEntity, unit); //send input to input manager } }
public Unit CreateUnit(Unit unitPrefab, Vector3 spawnPosition, Quaternion spawnRotation, Vector3 gotoPosition, int factionID, Building createdBy, bool free = false, bool updatePopluation = false) { if (GameManager.MultiplayerGame == false) //single player game { return(CreateUnitLocal(unitPrefab, spawnPosition, spawnRotation, gotoPosition, factionID, createdBy, free, updatePopluation)); //directly create new unit instance } else //if this is a multiplayer { //if it's a MP game, then ask the server to spawn the unit. //send input action to the input manager NetworkInput NewInputAction = new NetworkInput { sourceMode = (byte)InputMode.create, targetMode = (byte)InputMode.unit, initialPosition = spawnPosition, targetPosition = gotoPosition, value = free ? 0 : (updatePopluation ? 2 : 1) //free unit: 0, faction unit without population update: 1, faction unit with population update: 2 }; InputManager.SendInput(NewInputAction, unitPrefab, createdBy); //send to input manager return(null); } }
//a method that launches an attack movement for a single unit public void LaunchAttack(Unit unit, FactionEntity targetEntity, Vector3 targetPosition, AttackModes attackMode, bool playerCommand) { if (GameManager.MultiplayerGame == false) //single player game, directly prepare the unit's attack movement { PrepareMove(unit, targetPosition, targetEntity ? targetEntity.GetRadius() : 0.0f, targetEntity, InputMode.attack, playerCommand, true, attackMode, targetEntity); } else if (RTSHelper.IsLocalPlayer(unit) == true) //multiplayer game and this is the local player { //send input action to the input manager NetworkInput newInput = new NetworkInput() { sourceMode = (byte)InputMode.unit, targetMode = (byte)InputMode.attack, initialPosition = unit.transform.position, targetPosition = targetPosition, value = (int)attackMode, }; //sent input InputManager.SendInput(newInput, unit, targetEntity); } }
//a method that converts this unit to the converter's faction public void Convert(Unit converter, int targetFactionID) { if (targetFactionID == FactionID) //if the converter and this unit have the same faction, then, what a waste of time and resources. { return; } if (GameManager.MultiplayerGame == false) //if this is a single player game { ConvertLocal(converter, targetFactionID); //convert unit directly } else if (RTSHelper.IsLocalPlayer(this)) //online game and this is the local player { NetworkInput newInput = new NetworkInput() { sourceMode = (byte)InputMode.unit, targetMode = (byte)InputMode.convert, initialPosition = transform.position, value = targetFactionID }; InputManager.SendInput(newInput, this, converter); //send conversion input to the input manager } }