Help with player control plugin
#1
I'm currently porting Bukkit's iControlU plugin to Cuberite. This plugin allows a player to control another player's movement and inventory, and chat as the player.

The movement part of the plugin works just fine, but I'm having trouble with the inventory and chat. What I want to do is to send the inventory of the controller to the target whenever the inventories are different from each other, without causing a deadlock. The inventory is sent, but eventually (or sometimes immediately) the server stops responding. As for the chat, is there a way to chat as another player at the moment?

Info.lua:
g_PluginInfo = {
	Name = "iControlU",
	Version = "1",
	Date = "2017-07-12",
	SourceLocation = "https://github.com/mathiascode/iControlU",
	Description = [[Plugin for Cuberite that allows players to control other players.]],

	Commands =
	{
		["/icu"] =
		{
			HelpString = "Control another player\'s movement",
			Permission = "icu.command",
			Subcommands =
			{
				control =
				{
					Alias = "c",
					Permission = "icu.control",
					Handler = HandleControlCommand,
				},
				stop =
				{
					Alias = "s",
					Permission = "icu.stop",
					Handler = HandleStopCommand,
				},
			},
		},
	},
	Permissions =
	{
		["icu.exempt"] =
		{
			Description = "Players with this permission cannot be controlled",
			RecommendedGroups = "everyone",
		},
	},
}

main.lua:
ControllerFor = {}
TargetFor = {}
Inventory = {}
GlobalTime = 0

function Initialize(Plugin)
	Plugin:SetName(g_PluginInfo.Name)
	Plugin:SetVersion(g_PluginInfo.Version)

	cPluginManager:AddHook(cPluginManager.HOOK_CHAT, OnChat)
	cPluginManager:AddHook(cPluginManager.HOOK_ENTITY_CHANGING_WORLD, OnEntityChangingWorld)
	cPluginManager:AddHook(cPluginManager.HOOK_EXECUTE_COMMAND, OnExecuteCommand)
	cPluginManager:AddHook(cPluginManager.HOOK_PLAYER_ANIMATION, OnPlayerAnimation)
	cPluginManager:AddHook(cPluginManager.HOOK_PLAYER_DESTROYED, OnPlayerDestroyed)
	cPluginManager:AddHook(cPluginManager.HOOK_PLAYER_LEFT_CLICK, OnPlayerLeftClick)
	cPluginManager:AddHook(cPluginManager.HOOK_PLAYER_MOVING, OnPlayerMoving)
	cPluginManager:AddHook(cPluginManager.HOOK_PLAYER_TOSSING_ITEM, OnPlayerTossingItem)
	cPluginManager:AddHook(cPluginManager.HOOK_TAKE_DAMAGE, OnTakeDamage)
	cPluginManager:AddHook(cPluginManager.HOOK_WORLD_TICK, OnWorldTick)

	dofile(cPluginManager:GetPluginsPath() .. "/InfoReg.lua")
	RegisterPluginInfoCommands()

	LOG("Initialised " .. Plugin:GetName() .. " v." .. Plugin:GetVersion())
	return true
end

	--for i=0,40 do
		--local Item = Inventory[Controller:GetUUID()]:GetSlot(i)
		--Controller:GetInventory():SetSlot(i, Item)
	--end
	--Inventory[Controller:GetUUID()] = nil

function HandleControlCommand(Split, Controller)
	if Split[3] == nil then
		Controller:SendMessageInfo("Usage: " .. Split[1] .. " " .. Split[2] .. " <player>")
	else
			local Control = function(Target)
				if Target == Controller then
					Controller:SendMessageFailure("You are already in control of yourself")
				elseif Target:HasPermission("icu.exempt") then
					Controller:SendMessageFailure("You can\'t control this player")
				else
					Controller:TeleportToEntity(Target)
					Inventory[Controller:GetUUID()] = Controller:GetInventory()
					for i=0,40 do
						Controller:GetInventory():SetSlot(i, Target:GetInventory():GetSlot(i))
					end
					ControllerFor[Target:GetUUID()] = Controller
					TargetFor[Controller:GetUUID()] = Target
					Controller:SendMessageSuccess("You are now controlling \"" .. Target:GetName() .. "\"")
				end
			end
			if Split[3] == "" or not cRoot:Get():FindAndDoWithPlayer(Split[3], Control) then
				Controller:SendMessageFailure("Player \"" .. Split[3] .. "\" not found")
				return true
			end
	end
	return true
end

function HandleStopCommand(Split, Controller)
	local Target = TargetFor[Controller:GetUUID()]
	if Target then
		ControllerFor[Target:GetUUID()] = nil
		TargetFor[Controller:GetUUID()] = nil
		Controller:GetWorld():ScheduleTask(200,
			function()
				Controller:SetVisible(true)
			end
		)
		Target:Unfreeze()
		Controller:SendMessageSuccess("You are no longer controlling \"" .. Target:GetName() .. "\". You are invisible for 10 seconds.")
	else
		Controller:SendMessageFailure("You are not controlling anyone at the moment")
	end
	return true
end

function OnChat(Target, Message)
	if ControllerFor[Target:GetUUID()] then
		Target:SendMessageInfo("You cannot chat while being controlled")
		return true
	end
end

function OnEntityChangingWorld(Controller, World)
        if Controller:IsPlayer() then
		local Target = TargetFor[Controller:GetUUID()]
		if Target then
			Target:MoveToWorld(Controller:GetWorld())
		end
        end
end

function OnExecuteCommand(Target, CommandSplit, EntireCommand)
	if Target and ControllerFor[Target:GetUUID()] then
		Target:SendMessageInfo("You cannot run commands while being controlled")
		return true
	end
end

function OnPlayerAnimation(Controller, Animation)
	local Target = TargetFor[Controller:GetUUID()]
	if Target then
		Controller:GetClientHandle():SendEntityAnimation(Target, Animation)
	end
end

function OnPlayerDestroyed(Player)
	cRoot:Get():ForEachPlayer(
		function(OtherPlayer)
			if ControllerFor[Player:GetUUID()] == OtherPlayer then
				ControllerFor[Player:GetUUID()] = nil
				TargetFor[OtherPlayer:GetUUID()] = nil
				OtherPlayer:GetWorld():ScheduleTask(200,
					function()
						OtherPlayer:SetVisible(true)
					end
				)
				OtherPlayer:SendMessageInfo("The player you were controlling has disconnected. You are invisible for 10 seconds.")
			end
			if TargetFor[Player:GetUUID()] == OtherPlayer then
				ControllerFor[OtherPlayer:GetUUID()] = nil
				TargetFor[Player:GetUUID()] = nil
				OtherPlayer:Unfreeze()
			end
		end
	)
end

function OnPlayerLeftClick(Target, BlockX, BlockY, BlockZ, BlockFace, Action)
	if ControllerFor[Target:GetUUID()] then
		return true
	end
end

function OnPlayerMoving(Target, OldPosition, NewPosition)
	if ControllerFor[Target:GetUUID()] then
		return true
	end
end

function OnPlayerRightClick(Target, BlockX, BlockY, BlockZ, BlockFace, CursorX, CursorY, CursorZ)
	if ControllerFor[Target:GetUUID()] then
		return true
	end
end

function OnPlayerTossingItem(Target)
	if ControllerFor[Target:GetUUID()] then
		return true
	end
end

function OnTakeDamage(Controller, TDI)
	if Controller:IsPlayer() then
		local Target = TargetFor[Controller:GetUUID()]
		if Target then
			Target:TakeDamage(TDI.DamageType, Controller, TDI.RawDamage, TDI.FinalDamage, TDI.Knockback)
		end
	end
end

function OnWorldTick(World, TimeDelta)
	cRoot:Get():ForEachPlayer(
		function(Target)
			local Controller = ControllerFor[Target:GetUUID()]
			if Controller then
				Target:TeleportToEntity(Controller)
				Target:SetSpeed(0,0,0)
				Target:Freeze(Target:GetPosition())
				Target:SendRotation(Controller:GetYaw(), Controller:GetPitch())
				Target:SetHeadYaw(Controller:GetHeadYaw())
				Target:SetYaw(Controller:GetYaw())
				Target:SetPitch(Controller:GetPitch())
				Target:SetIsFireproof(Controller:IsFireproof())
				Target:SetGameMode(Controller:GetGameMode())
				Target:SetCrouch(Controller:IsCrouched())
				Target:SetFlying(Controller:IsFlying())
				Target:SetFoodLevel(Controller:GetFoodLevel())
				Target:SetSprint(Controller:IsSprinting())
				Controller:SetVisible(false)
        			if GlobalTime == 20 then
					if Controller:GetInventory() ~= Target:GetInventory() then
						for i=0,40 do
							local Slot = Controller:GetInventory():GetSlot(i)
							Target:GetInventory():SetSlot(i, Slot)
						end
					end
                                else
					GlobalTime = GlobalTime + 1
				end
			end
		end
	)
end

function OnDisable()
        cRoot:Get():ForEachPlayer(
		function(Controller)
			local Target = TargetFor[Controller:GetUUID()]
			if Target then
				Target:Unfreeze()
				Controller:SetVisible(true)
				Controller:SendMessageInfo("You are no longer controlling a player due to server reload")
			end
		end
	)
	LOG("Disabled " .. cPluginManager:GetCurrentPlugin():GetName() .. "!")
end
Reply
Thanks given by:


Messages In This Thread
Help with player control plugin - by Mathias - 07-12-2017, 08:30 AM
RE: Help with player control plugin - by NiLSPACE - 07-12-2017, 05:00 PM
RE: Help with player control plugin - by Mathias - 07-12-2017, 09:37 PM
RE: Help with player control plugin - by NiLSPACE - 07-12-2017, 09:48 PM
RE: Help with player control plugin - by Mathias - 11-27-2017, 06:39 AM



Users browsing this thread: 1 Guest(s)