private OperationResponse ItemOperationDestroy(MmoActor actor, Item item, DestroyItem operation) { MethodReturnValue result = this.CheckAccess(item, actor); if (result) { item.Destroy(); item.Dispose(); actor.RemoveItem(item); (item.world as MmoWorld).ItemCache.RemoveItem(item.Type, item.Id); var eventInstance = new ItemDestroyed { ItemId = item.Id, ItemType = item.Type }; var eventData = new EventData((byte)EventCode.ItemDestroyed, eventInstance); actor.Peer.SendEvent(eventData, new SendParameters { ChannelId = Settings.ItemEventChannel }); // no response, event is sufficient operation.OnComplete(); return(null); } return(operation.GetOperationResponse(result)); }
private void ExitWorld(MmoActor actor) { //reset target when exiting world actor.GetComponent <PlayerTarget>().Clear(); actor.GetComponent <PlayerLoaderObject>().Save(true); var worldExited = new WorldExited { WorldName = ((MmoWorld)actor.World).Name }; actor.nebulaObject.SetInvisibility(false); actor.Dispose(); // set initial handler ((MmoPeer)actor.Peer).SetCurrentOperationHandler((MmoPeer)actor.Peer); var eventData = new EventData((byte)EventCode.WorldExited, worldExited); actor.UpdateCharacterOnMaster(); // use item channel to ensure that this event arrives in correct order with move/subscribe events actor.Peer.SendEvent(eventData, new SendParameters { ChannelId = Settings.ItemEventChannel }); CL.Out(LogFilter.PLAYER, "ExitWorld() Player {0} from world {1}".f(actor.name, ((MmoWorld)actor.World).Name)); }
public override OperationResponse Handle(MmoActor player, OperationRequest request, SendParameters sendParameters) { GetWorldsOperation operation = new GetWorldsOperation(player.Peer.Protocol, request); if (!operation.IsValid) { return(new OperationResponse(request.OperationCode) { ReturnCode = (short)ReturnCode.InvalidOperationParameter, DebugMessage = "Invalid operation parameters" }); } var dict = player.application.DatabaseManager.GetWorlds(); Hashtable worldHash = new Hashtable(); foreach (var p in dict) { worldHash.Add(p.Key, p.Value.GetInfo()); } GetWorldsOperationResponse responseObject = new GetWorldsOperationResponse { worlds = worldHash }; return(new OperationResponse(request.OperationCode, responseObject)); }
private void Startup() { if (!mInitialized) { mInitialized = true; mEnergy = RequireComponent <ShipEnergyBlock>(); mRace = RequireComponent <RaceableObject>(); mShip = GetComponent <BaseShip>(); var character = GetComponent <CharacterObject>(); var dropManager = DropManager.Get(nebulaObject.world.Resource()); var player = GetComponent <MmoActor>(); if (player != null) { } else { InitializeAsBot(); } mPlayer = GetComponent <MmoActor>(); //log.Info("ShipWeapon.Start() completed"); } }
public override OperationResponse Handle(MmoActor player, OperationRequest request, SendParameters sendParameters) { GetShipModel operation = new GetShipModel(player.Peer.Protocol, request); if (!operation.IsValid) { return(new OperationResponse(request.OperationCode) { ReturnCode = (short)ReturnCode.InvalidOperationParameter, DebugMessage = operation.GetErrorMessage() }); } var playerShip = player.GetComponent <PlayerShip>(); if (playerShip == null || playerShip.shipModel == null) { return(new OperationResponse(request.OperationCode) { ReturnCode = (short)ReturnCode.Fatal, DebugMessage = "Player ship or ship model don't exists" }); } GetShipModelResponse responseObject = new GetShipModelResponse { model = playerShip.shipModel.GetExistingInfo() }; return(new OperationResponse(request.OperationCode, responseObject)); }
private ServerInventoryItem GiveOreReward(MmoActor player, ContractOreDataReward oreReward) { int playerLevel = player.GetComponent <CharacterObject>().level; OreData data = null; foreach (var ore in player.resource.Materials.Ores) { if (ore.Id.Contains(playerLevel.ToString())) { data = ore; break; } } if (data != null) { MaterialObject materialObj = new MaterialObject(data.Id); int count = Rand.Int(oreReward.minCount, oreReward.maxCount); if (count > 0) { ServerInventoryItem item = new ServerInventoryItem(materialObj, count); return(item); } } return(null); }
private OperationResponse CallResetSystemToNeutral(MmoActor player, OperationRequest request, RPCInvokeOperation op) { var forts = (player.World as MmoWorld).FindObjectsOfType <Outpost>(); foreach (var kf in forts) { (kf.Value.nebulaObject as GameObject).Destroy(); } s_Log.InfoFormat("removed: {0} fortifications", forts.Count); var outposts = (player.World as MmoWorld).FindObjectsOfType <MainOutpost>(); foreach (var kf in outposts) { (kf.Value.nebulaObject as GameObject).Destroy(); } s_Log.InfoFormat("removed: {0} outposts", outposts.Count); forts.Clear(); outposts.Clear(); (player.World as MmoWorld).SetUnderAttack(false); (player.World as MmoWorld).SetCurrentRace(Race.None); RPCInvokeResponse respInstance = new RPCInvokeResponse { rpcId = op.rpcId, result = new Hashtable { { (int)SPC.ReturnCode, (int)RPCErrorCode.Ok } } }; return(new OperationResponse(request.OperationCode, respInstance)); }
/// <summary> /// Unlock all existing lore operation /// </summary> private OperationResponse CallUnlockAllLore(MmoActor player, OperationRequest request, RPCInvokeOperation op) { string[] humanStory = new string[] { "st_0_rec_0", "st_0_rec_1", "st_0_rec_2", "st_0_rec_3", "st_0_rec_4", "st_0_rec_5", "st_0_rec_6", "st_0_rec_7", "st_0_rec_8", "st_0_rec_9", "st_0_rec_10", "st_0_rec_11", "st_0_rec_12", "st_0_rec_13", "st_0_rec_14", "st_0_rec_15", "st_0_rec_16", "st_0_rec_17", "st_0_rec_18", "st_0_rec_19" }; string[] criptizidStory = new string[] { "st_1_rec_0", "st_1_rec_1", "st_1_rec_2", "st_1_rec_3", "st_1_rec_4", "st_1_rec_5", "st_1_rec_6", "st_1_rec_7", "st_1_rec_8", "st_1_rec_9", "st_1_rec_10", "st_1_rec_11", "st_1_rec_12", "st_1_rec_13", "st_1_rec_14", "st_1_rec_15", "st_1_rec_16", "st_1_rec_17", "st_1_rec_18", "st_1_rec_19" }; string[] borgStory = new string[] { "st_2_rec_0", "st_2_rec_1", "st_2_rec_2", "st_2_rec_3", "st_2_rec_4", "st_2_rec_5", "st_2_rec_6", "st_2_rec_7", "st_2_rec_8", "st_2_rec_9" }; var achievmentComponent = player.GetComponent <AchievmentComponent>(); foreach (string id in humanStory) { achievmentComponent.FoundLoreRecord(id); } foreach (string id in criptizidStory) { achievmentComponent.FoundLoreRecord(id); } foreach (string id in borgStory) { achievmentComponent.FoundLoreRecord(id); } RPCInvokeResponse responseInstance = new RPCInvokeResponse { rpcId = op.rpcId }; responseInstance.result = new Hashtable { { (int)SPC.ReturnCode, (int)RPCErrorCode.LoreRecordAlreadyUnlocked } }; return(new OperationResponse(request.OperationCode, responseInstance)); }
/// <summary> /// Handle start collecting asteroid action. Receive request from client and send StartCollectAsteroid generic event to all subscribers /// </summary> private OperationResponse CallStartAsteroidCollecting(MmoActor player, OperationRequest request, RPCInvokeOperation op) { if (op.parameters != null && op.parameters.Length >= 2) { byte containerType = (byte)op.parameters[0]; string containerId = (string)op.parameters[1]; var mmoComponent = player.GetComponent <MmoMessageComponent>(); if (mmoComponent) { mmoComponent.PublishStartAsteroidCollecting(containerType, containerId); } RPCInvokeResponse responseInstance = new RPCInvokeResponse { rpcId = op.rpcId, result = new Hashtable { { (int)SPC.ReturnCode, (int)RPCErrorCode.Ok }, { (int)SPC.ItemId, containerId }, { (int)SPC.ItemType, containerType } } }; return(new OperationResponse(request.OperationCode, responseInstance)); } else { return(InvalidOperationParameter(request)); } }
public override OperationResponse Handle(MmoActor actor, OperationRequest request, SendParameters sendParameters) { var operation = new SetProperties(actor.Peer.Protocol, request); if (!operation.IsValid) { return(new OperationResponse(request.OperationCode) { ReturnCode = (int)ReturnCode.InvalidOperationParameter, DebugMessage = operation.GetErrorMessage() }); } operation.OnStart(); Item item; if (false == operation.ItemType.HasValue || string.IsNullOrEmpty(operation.ItemId)) { item = actor.Avatar; // set return values operation.ItemId = item.Id; operation.ItemType = item.Type; } else if (actor.TryGetItem(operation.ItemType.Value, operation.ItemId, out item) == false) { return(operation.GetOperationResponse((int)ReturnCode.ItemNotFound, "ItemNotFound")); } return(this.ItemOperationSetProperties(item, operation, sendParameters, actor)); }
private OperationResponse CallTestKill(MmoActor player, OperationRequest request, RPCInvokeOperation op) { bool success = false; var targetComponent = player.GetComponent <PlayerTarget>(); if (targetComponent.targetObject != null) { var targetDamagableComponent = targetComponent.targetObject.GetComponent <DamagableObject>(); if (targetDamagableComponent != null) { WeaponDamage weaponDamage = new WeaponDamage(WeaponBaseType.Rocket, 100000, 0, 0); DamageParams damageParams = new DamageParams(); damageParams.SetReflrected(false); damageParams.SetIgnoreFixedDamage(true); targetDamagableComponent.ReceiveDamage(new InputDamage(player.nebulaObject, weaponDamage, damageParams)); success = true; } } RPCInvokeResponse responseInstance = new RPCInvokeResponse { rpcId = op.rpcId, result = success }; return(new OperationResponse(request.OperationCode, responseInstance)); }
public override void Start() { base.Start(); mShip = RequireComponent <BaseShip>(); mBonuses = RequireComponent <PlayerBonuses>(); if (GetComponent <PlayerLoaderObject>()) { log.Info("load before destructable"); GetComponent <PlayerLoaderObject>().Load(); } float initHealth = maximumHealth; if (initHealth <= 0.0f) { initHealth = 1000000; } //log.InfoFormat("Set health at start to {0}", initHealth); ForceSetHealth(initHealth); mpcHPRegenNonCombatPerSec = nebulaObject.resource.ServerInputs.GetValue <float>("hp_regen_non_combat"); player = GetComponent <MmoActor>(); mTarget = GetComponent <PlayerTarget>(); mSkills = GetComponent <PlayerSkills>(); mPassiveBonuses = GetComponent <PassiveBonusesComponent>(); //mEventedObject = GetComponent<EventedObject>(); m_Message = GetComponent <MmoMessageComponent>(); }
public override OperationResponse Handle(MmoActor actor, OperationRequest request, SendParameters sendParameters) { var operation = new DetachInterestArea(actor.Peer.Protocol, request); if (!operation.IsValid) { return(new OperationResponse(request.OperationCode) { ReturnCode = (int)ReturnCode.InvalidOperationParameter, DebugMessage = operation.GetErrorMessage() }); } operation.OnStart(); InterestArea interestArea; if (actor.TryGetInterestArea(operation.InterestAreaId, out interestArea) == false) { return(operation.GetOperationResponse((int)ReturnCode.InterestAreaNotFound, "InterestAreaNotFound")); } lock (interestArea.SyncRoot) { interestArea.Detach(); } return(operation.GetOperationResponse(MethodReturnValue.Ok)); }
private RPCErrorCode CheckAnaluzer001(MmoActor player) { var activators = player.nebulaObject.mmoWorld().GetItems((item) => { var activator = item.GetComponent <ActivatorObject>(); if (activator != null) { if (item.badge == "shipwreck") { return(true); } } return(false); }); if (activators.Count == 0) { return(RPCErrorCode.NoValidObjects); } foreach (var kvp in activators) { var item = kvp.Value; float dist = player.transform.DistanceTo(kvp.Value.transform); var activator = item.GetComponent <ActivatorObject>(); if (dist < activator.radius + item.size) { return(RPCErrorCode.Ok); } } return(RPCErrorCode.DistanceIsFar); }
public override OperationResponse Handle(MmoActor actor, OperationRequest request, SendParameters sendParameters) { var operation = new MoveInterestArea(actor.Peer.Protocol, request); if (!operation.IsValid) { return(new OperationResponse(request.OperationCode) { ReturnCode = (int)ReturnCode.InvalidOperationParameter, DebugMessage = operation.GetErrorMessage() }); } operation.OnStart(); InterestArea interestArea; if (actor.TryGetInterestArea(operation.InterestAreaId, out interestArea)) { lock (interestArea.SyncRoot) { interestArea.Position = operation.Position.ToVector(true); interestArea.UpdateInterestManagement(); } // don't send response return(null); } return(operation.GetOperationResponse((int)ReturnCode.InterestAreaNotFound, "InterestAreaNotFound")); }
private OperationResponse CallResetNew(MmoActor player, OperationRequest request, RPCInvokeOperation op) { if (op.parameters != null && op.parameters.Length >= 1) { InventoryType inventoryType = (InventoryType)(byte)op.parameters[0]; bool success = true; if (inventoryType == InventoryType.ship) { player.Inventory.ResetNew(); } else if (inventoryType == InventoryType.station) { player.Station.StationInventory.ResetNew(); } else { success = false; } RPCInvokeResponse responseInstance = new RPCInvokeResponse { rpcId = op.rpcId, result = success }; return(new OperationResponse(request.OperationCode, responseInstance)); } return(InvalidOperationParameter(request)); }
public override OperationResponse Handle(MmoActor actor, OperationRequest request, SendParameters sendParameters) { //var operation = new SpawnItem(actor.Peer.Protocol, request); //if (!operation.IsValid) { // return new OperationResponse(request.OperationCode) { ReturnCode = (int)ReturnCode.InvalidOperationParameter, DebugMessage = operation.GetErrorMessage() }; //} //operation.OnStart(); //InterestArea interestArea; //if (operation.InterestAreaId.HasValue) { // if (actor.TryGetInterestArea(operation.InterestAreaId.Value, out interestArea) == false) { // return operation.GetOperationResponse((int)ReturnCode.InterestAreaNotFound, "InterestAreaNotFound"); // } //} else { // interestArea = null; //} //IWorld world = actor.World; //var item = new MmoItem(world, operation.Position, operation.Rotation, operation.Properties, actor, operation.ItemId, operation.ItemType); //if (world.ItemCache.AddItem(item)) { // actor.AddItem(item); // return this.ItemOperationSpawn(item, operation, interestArea, actor); //} //item.Dispose(); //return operation.GetOperationResponse((int)ReturnCode.ItemAlreadyExists, "ItemAlreadyExists"); return(new OperationResponse(request.OperationCode)); }
private static void CreateNewItem(MmoActor player) { var oldItem = player.nebulaObject as MmoItem; var interestArea = new MmoClientInterestArea(player.Peer, 0, player.World) { ViewDistanceEnter = new GameMath.Vector { X = 50000, Y = 50000, Z = 50000 }, ViewDistanceExit = new GameMath.Vector { X = 100000, Y = 100000, Z = 100000 } }; var newITem = new MmoItem(player.Peer, interestArea, player.World, player.application, player.transform.position.ToArray(), player.transform.rotation.ToArray(), new System.Collections.Hashtable(), player.nebulaObject.Id, player.nebulaObject.tags, player.nebulaObject.size, player.nebulaObject.subZone, oldItem.allBehaviours); log.InfoFormat("why why why green"); player.GetComponent <DamagableObject>().SetIgnoreDamageAtStart(true); player.GetComponent <DamagableObject>().SetIgnoreDamageInterval(30); oldItem.Dispose(); }
private OperationResponse CallSetPlayerMark(MmoActor player, OperationRequest request, RPCInvokeOperation op) { if (op.parameters != null && op.parameters.Length >= 2) { string id = (string)op.parameters[0]; byte type = (byte)op.parameters[1]; var targetComponent = player.GetComponent <PlayerTarget>(); if (targetComponent != null) { if (string.IsNullOrEmpty(id)) { targetComponent.ClearMarkedItem(); } else { targetComponent.SetMarkedItem(id, type); } RPCInvokeResponse responseInstance = new RPCInvokeResponse { rpcId = op.rpcId, result = true }; return(new OperationResponse(request.OperationCode, responseInstance)); } } return(InvalidOperationParameter(request)); }
private OperationResponse CallUseCreditsBag(MmoActor player, OperationRequest request, RPCInvokeOperation op) { if (op.parameters != null && op.parameters.Length >= 1) { string itemId = (string)op.parameters[0]; ServerInventoryItem creditsBagItem; if (player.Station.StationInventory.TryGetItem(InventoryObjectType.credits_bag, itemId, out creditsBagItem)) { if (creditsBagItem.Count > 0) { int count = (creditsBagItem.Object as CreditsBagObject).count; player.ActionExecutor._AddCredits(count); player.Station.StationInventory.Remove(InventoryObjectType.credits_bag, itemId, 1); player.EventOnStationHoldUpdated(); RPCInvokeResponse respInstance = new RPCInvokeResponse { rpcId = op.rpcId, result = new Hashtable { { (int)SPC.ReturnCode, (int)RPCErrorCode.Ok }, { (int)SPC.Count, count } } }; return(new OperationResponse(request.OperationCode, respInstance)); } else { return(ErrorResponse(request, op.rpcId, RPCErrorCode.CountIsZero)); } } else { return(ErrorResponse(request, op.rpcId, RPCErrorCode.ItemNotFound)); } } return(InvalidOperationParameter(request)); }
public override OperationResponse Handle(MmoActor actor, OperationRequest request, SendParameters sendParameters) { var operation = new SetViewDistance(actor.Peer.Protocol, request); if (!operation.IsValid) { return(new OperationResponse(request.OperationCode) { ReturnCode = (int)ReturnCode.InvalidOperationParameter, DebugMessage = operation.GetErrorMessage() }); } operation.OnStart(); InterestArea interestArea; if (actor.TryGetInterestArea(operation.InterestAreaId, out interestArea) == false) { return(operation.GetOperationResponse((int)ReturnCode.InterestAreaNotFound, "InterestAreaNotFound")); } lock (interestArea.SyncRoot) { interestArea.ViewDistanceEnter = operation.ViewDistanceEnter.ToVector(true); interestArea.ViewDistanceExit = operation.ViewDistanceExit.ToVector(true); interestArea.UpdateInterestManagement(); } log.InfoFormat("setted interest area min = {0} max = {1}", interestArea.ViewDistanceEnter, interestArea.ViewDistanceExit); // don't send response return(null); }
public override void Start() { hasTarget = false; targetId = string.Empty; targetType = (byte)ItemType.Avatar; UnsubscribeFromTarget(); mPlayer = GetComponent <MmoActor>(); }
/// <summary> /// Handles operation <see cref = "AttachInterestArea" />: Attaches an existing <see cref = "InterestArea" /> to an existing <see cref = "Item" />. /// </summary> /// <param name = "peer"> /// The client peer. /// </param> /// <param name = "request"> /// The request. /// </param> /// <param name = "sendParameters"> /// The send Parameters. /// </param> /// <returns> /// An <see cref = "OperationResponse" /> with error code <see cref = "ReturnCode.Ok" />, <see cref = "ReturnCode.InterestAreaNotFound" /> or <see cref = "ReturnCode.ItemNotFound" />. /// </returns> public override OperationResponse Handle(MmoActor actor, OperationRequest request, SendParameters sendParameters) { var operation = new AttachInterestArea(actor.Peer.Protocol, request); if (!operation.IsValid) { return(new OperationResponse(request.OperationCode) { ReturnCode = (int)ReturnCode.InvalidOperationParameter, DebugMessage = operation.GetErrorMessage() }); } operation.OnStart(); InterestArea interestArea; if (actor.TryGetInterestArea(operation.InterestAreaId, out interestArea) == false) { return(operation.GetOperationResponse((int)ReturnCode.InterestAreaNotFound, "InterestAreaNotFound")); } Item item; bool actorItem; if (false == operation.ItemType.HasValue || string.IsNullOrEmpty(operation.ItemId)) { item = actor.Avatar; actorItem = true; // set return vaues operation.ItemId = item.Id; operation.ItemType = item.Type; } else { IWorld world = actor.World; actorItem = actor.TryGetItem(operation.ItemType.Value, operation.ItemId, out item); if (actorItem == false) { if (world.ItemCache.TryGetItem(operation.ItemType.Value, operation.ItemId, out item) == false) { return(operation.GetOperationResponse((int)ReturnCode.ItemNotFound, "ItemNotFound")); } } } if (actorItem) { // we are already in the item thread, invoke directly return(this.ItemOperationAttachInterestArea(actor, item, operation, interestArea, sendParameters)); } // second parameter (peer) allows us to send an error event to the client (in case of an error) item.Fiber.Enqueue( () => actor.ExecItemOperation(() => this.ItemOperationAttachInterestArea(actor, item, operation, interestArea, sendParameters), sendParameters)); // response is sent later return(null); }
public static void ChangeMobToChaseState(string mobId, MmoActor targetPlayerItem) { bool hasKey = mobTable.ContainsKey(mobId); if (hasKey) { mobTable[mobId].ChangeToChaseState(targetPlayerItem); } }
public override OperationResponse Handle(MmoActor actor, OperationRequest request, SendParameters sendParameters) { var operation = new Operation(); operation.OnStart(); ExitWorkshop(actor); operation.OnComplete(); return(null); }
public override OperationResponse Handle(MmoActor actor, OperationRequest request, SendParameters sendParameters) { var operation = new RequestServerID(actor.Peer.Protocol, request); RequestServerIDResponse responseObject = new RequestServerIDResponse { id = GameApplication.ServerId.ToString() }; return(new OperationResponse(request.OperationCode, responseObject)); }
private OperationResponse CallRestartLoop(MmoActor player, OperationRequest request, RPCInvokeOperation op) { int result = player.ActionExecutor.RestartLoop(); RPCInvokeResponse r = new RPCInvokeResponse { rpcId = op.rpcId, result = result }; return(new OperationResponse(request.OperationCode, r)); }
private OperationResponse CallCreateTestSharedChest(MmoActor player, OperationRequest request, RPCInvokeOperation op) { RPCInvokeResponse responseInstance = new RPCInvokeResponse { rpcId = op.rpcId, result = player.ActionExecutor.CreateTestSharedChest() }; return(new OperationResponse(request.OperationCode, responseInstance)); }
private OperationResponse CallGetCells(MmoActor player, OperationRequest request, RPCInvokeOperation op) { RPCInvokeResponse respInstance = new RPCInvokeResponse { rpcId = op.rpcId, result = player.nebulaObject.mmoWorld().GetCellInfo() }; return(new OperationResponse(request.OperationCode, respInstance)); }
private OperationResponse CallGetAchievments(MmoActor player, OperationRequest request, RPCInvokeOperation op) { Hashtable hash = player.ActionExecutor.GetAchievmentInfo(); RPCInvokeResponse responseInstance = new RPCInvokeResponse { rpcId = op.rpcId, result = hash }; return(new OperationResponse(request.OperationCode, responseInstance)); }
public OperationResponse OperationEnterWorld(PeerBase peer, OperationRequest request, SendParameters sendParameters) { var operation = new EnterWorld(peer.Protocol, request); if (!operation.IsValid) { return new OperationResponse(request.OperationCode) { ReturnCode = (int)ErrorCode.InvalidOperationParameter, DebugMessage = operation.GetErrorMessage() }; } MmoWorld world = MmoWorld.Instance; var actor = new MmoActor(peer, world, interestArea); var avatar = new MmoItem(world, operation.Position, operation.Rotation, operation.Properties, actor, operation.Username, (byte)ItemType.Avatar); while (world.ItemCache.AddItem(avatar) == false) { Item otherAvatarItem; if (world.ItemCache.TryGetItem(avatar.Type, avatar.Id, out otherAvatarItem)) { avatar.Dispose(); actor.Dispose(); interestArea.Dispose(); ((Peer)((MmoItem)otherAvatarItem).Owner.Peer).DisconnectByOtherPeer(this, request, sendParameters); // request continued later, no response here return null; } } // init avatar actor.AddItem(avatar); actor.Avatar = avatar; ((Peer)peer).SetCurrentOperationHandler(actor); // set return values var responseObject = new EnterWorldResponse { }; // send response; use item channel to ensure that this event arrives before any move or subscribe events var response = new OperationResponse(request.OperationCode, responseObject); sendParameters.ChannelId = Settings.ItemEventChannel; peer.SendOperationResponse(response, sendParameters); avatar.Spawn(operation.Position); // response already sent return null; }