TOOL.Category = "Construction"
TOOL.Name = "#tool.stacker.name"
TOOL.ClientConVar["mode"] = "1"
TOOL.ClientConVar["dir"] = "1"
TOOL.ClientConVar["count"] = "1"
TOOL.ClientConVar["material"] = "1"
TOOL.ClientConVar["physprop"] = "1"
TOOL.ClientConVar["color"] = "1"
TOOL.ClientConVar["rendermode"] = "1"
TOOL.ClientConVar["offsetx"] = "0"
TOOL.ClientConVar["offsety"] = "0"
TOOL.ClientConVar["offsetz"] = "0"
TOOL.ClientConVar["rotp"] = "0"
TOOL.ClientConVar["roty"] = "0"
TOOL.ClientConVar["rotr"] = "0"
TOOL.ClientConVar["recalc"] = "0"

TOOL.Information = {
	{name = "left"},
	{name = "right"},
	{name = "reload"}
}

if CLIENT then
	language.Add("tool.stacker.name", "Stacker")
	language.Add("tool.stacker.desc", "Hiermit können Props gestapelt werden.")
	language.Add("tool.stacker.left", "Stapelt Props")
	language.Add("tool.stacker.right", "Ändert Richtung")
	language.Add("tool.stacker.reload", "Setzt alle Abstände zurück")
	language.Add("Undone_Stacker", "Undone Stacked Prop(s)")
end

local MODE_WORLD = 1
local MODE_PROP  = 2
local DIRECTION_UP = 1
local DIRECTION_DOWN = 2
local DIRECTION_FRONT = 3
local DIRECTION_BACK = 4
local DIRECTION_RIGHT = 5
local DIRECTION_LEFT = 6
local ANGLE_ZERO = Angle(0, 0, 0)
local VECTOR_FRONT = ANGLE_ZERO:Forward()
local VECTOR_RIGHT = ANGLE_ZERO:Right()
local VECTOR_UP = ANGLE_ZERO:Up()
local VECTOR_BACK = -VECTOR_FRONT
local VECTOR_LEFT = -VECTOR_RIGHT
local VECTOR_DOWN = -VECTOR_UP

local DirectionFunctions = {
	[MODE_WORLD] = {
		[DIRECTION_FRONT] = function() return VECTOR_FRONT end,
		[DIRECTION_BACK] = function() return VECTOR_BACK end,
		[DIRECTION_RIGHT] = function() return VECTOR_RIGHT end,
		[DIRECTION_LEFT] = function() return VECTOR_LEFT end,
		[DIRECTION_UP] = function() return VECTOR_UP end,
		[DIRECTION_DOWN] = function() return VECTOR_DOWN end
	},
	[MODE_PROP]  = {
		[DIRECTION_FRONT] = function(ang) return ang:Forward() end,
		[DIRECTION_BACK] = function(ang) return -ang:Forward() end,
		[DIRECTION_RIGHT] = function(ang) return ang:Right() end,
		[DIRECTION_LEFT] = function(ang) return -ang:Right() end,
		[DIRECTION_UP] = function(ang) return ang:Up() end,
		[DIRECTION_DOWN] = function(ang) return -ang:Up() end
	}
}

local DistanceFunctions = {
	[DIRECTION_FRONT] = function(min, max) return math.abs(max.x - min.x) end,
	[DIRECTION_BACK] = function(min, max) return math.abs(max.x - min.x) end,
	[DIRECTION_RIGHT] = function(min, max) return math.abs(max.y - min.y) end,
	[DIRECTION_LEFT] = function(min, max) return math.abs(max.y - min.y) end,
	[DIRECTION_UP] = function(min, max) return math.abs(max.z - min.z) end,
	[DIRECTION_DOWN] = function(min, max) return math.abs(max.z - min.z) end
}

local OffsetFunctions = {
	[DIRECTION_FRONT] = function(ang, offset) return (ang:Forward() * offset.x) + (ang:Up() * offset.z) + (ang:Right() * offset.y) end,
	[DIRECTION_BACK] = function(ang, offset) return (-ang:Forward() * offset.x) + (ang:Up() * offset.z) + (-ang:Right() * offset.y) end,
	[DIRECTION_RIGHT] = function(ang, offset) return (ang:Right() * offset.x) + (ang:Up() * offset.z) + (-ang:Forward() * offset.y) end,
	[DIRECTION_LEFT] = function(ang, offset) return (-ang:Right() * offset.x) + (ang:Up() * offset.z) + (ang:Forward() * offset.y) end,
	[DIRECTION_UP] = function(ang, offset) return (ang:Up() * offset.x) + (-ang:Forward() * offset.z) + (ang:Right() * offset.y) end,
	[DIRECTION_DOWN]  = function(ang, offset) return (-ang:Up() * offset.x) + (ang:Forward() * offset.z) + (ang:Right() * offset.y) end
}

local RotationFunctions = {
	[DIRECTION_FRONT] = function(ang) return  ang:Right(), ang:Up(), ang:Forward() end,
	[DIRECTION_BACK] = function(ang) return -ang:Right(), ang:Up(), -ang:Forward() end,
	[DIRECTION_RIGHT] = function(ang) return -ang:Forward(), ang:Up(), ang:Right() end,
	[DIRECTION_LEFT] = function(ang) return  ang:Forward(), ang:Up(), -ang:Right() end,
	[DIRECTION_UP] = function(ang) return -ang:Right(), ang:Forward(), ang:Up() end,
	[DIRECTION_DOWN] = function(ang) return  ang:Right(), ang:Forward(), -ang:Up() end
}

function GetDirection(mode, dir, ang)
	return DirectionFunctions[mode][dir](ang)
end

function GetDistance(mode, dir, ent)
	if mode == MODE_WORLD then
		return DistanceFunctions[dir](ent:WorldSpaceAABB())
	elseif mode == MODE_PROP then
		return DistanceFunctions[dir](ent:OBBMins(), ent:OBBMaxs())
	end
end

local MAGIC_OFFSET = -0.51
function GetOffset(mode, dir, ang, offset)
	if mode == MODE_WORLD then
		local direction = DirectionFunctions[mode][dir]()
		direction = direction * MAGIC_OFFSET
		return offset + direction
	elseif mode == MODE_PROP then
		local offset2 = Vector()
		offset2:Set(offset)
		offset2.x = offset2.x + MAGIC_OFFSET
		return OffsetFunctions[dir](ang, offset2)
	end
end

local function RotateAngle(mode, dir, ang, rotation)
	local pitch, yaw, roll = RotationFunctions[dir](ang)
	ang:RotateAroundAxis(pitch, rotation.p)
	ang:RotateAroundAxis(yaw, -rotation.y)
	ang:RotateAroundAxis(roll, rotation.r)
end

local TRANSPARENT = Color(255, 255, 255, 150)

CreateConVar("stacker_max_count", 3, bit.bor(FCVAR_NOTIFY, FCVAR_REPLICATED, FCVAR_SERVER_CAN_EXECUTE))
CreateConVar("stacker_max_offsetx", 200, bit.bor(FCVAR_NOTIFY, FCVAR_REPLICATED, FCVAR_SERVER_CAN_EXECUTE))
CreateConVar("stacker_max_offsety", 200, bit.bor(FCVAR_NOTIFY, FCVAR_REPLICATED, FCVAR_SERVER_CAN_EXECUTE))
CreateConVar("stacker_max_offsetz", 200, bit.bor(FCVAR_NOTIFY, FCVAR_REPLICATED, FCVAR_SERVER_CAN_EXECUTE))
CreateConVar("stacker_stayinworld", 0, bit.bor(FCVAR_NOTIFY, FCVAR_REPLICATED, FCVAR_SERVER_CAN_EXECUTE))
CreateConVar("stacker_delay", 0.1, bit.bor(FCVAR_NOTIFY, FCVAR_REPLICATED, FCVAR_SERVER_CAN_EXECUTE))

if CLIENT then
	local function ResetOffsets(ply, command, arguments)
		RunConsoleCommand("stacker_offsetx", "0")
		RunConsoleCommand("stacker_offsety", "0")
		RunConsoleCommand("stacker_offsetz", "0")
		RunConsoleCommand("stacker_rotp", "0")
		RunConsoleCommand("stacker_roty", "0")
		RunConsoleCommand("stacker_rotr", "0")
	end
	concommand.Add("stacker_resetoffsets", ResetOffsets)
end

local GhostStack = {}
local function GetGhostStack()
	return GhostStack
end

local function SetGhostStack(tbl)
	GhostStack = tbl
end

function TOOL:GetCount() 
	return math.Clamp(self:GetClientNumber("count"), 0, GetConVar("stacker_max_count"):GetInt()) 
end

function TOOL:GetDirection()
	return self:GetClientNumber("dir")
end

function TOOL:GetStackerMode()
	return self:GetClientNumber("mode")
end

function TOOL:GetOffsetX()
	return math.Clamp(self:GetClientNumber("offsetx"), - GetConVar("stacker_max_offsetx"):GetFloat(), GetConVar("stacker_max_offsetx"):GetFloat())
end

function TOOL:GetOffsetY()
	return math.Clamp(self:GetClientNumber("offsety"), - GetConVar("stacker_max_offsety"):GetFloat(), GetConVar("stacker_max_offsety"):GetFloat())
end

function TOOL:GetOffsetZ()
	return math.Clamp(self:GetClientNumber("offsetz"), - GetConVar("stacker_max_offsetz"):GetFloat(), GetConVar("stacker_max_offsetz"):GetFloat())
end

function TOOL:GetOffsetVector()
	return Vector(self:GetOffsetX(), self:GetOffsetY(), self:GetOffsetZ())
end

function TOOL:GetRotateP()
	return math.Clamp(self:GetClientNumber("rotp"), -360, 360)
end

function TOOL:GetRotateY()
	return math.Clamp(self:GetClientNumber("roty"), -360, 360)
end

function TOOL:GetRotateR()
	return math.Clamp(self:GetClientNumber("rotr"), -360, 360)
end

function TOOL:GetRotateAngle()
	return Angle(self:GetRotateP(), self:GetRotateY(), self:GetRotateR())
end

function TOOL:ShouldStackRelative()
	return self:GetClientNumber("recalc") == 1
end

function TOOL:ShouldApplyMaterial()
	return self:GetClientNumber("material") == 1
end

function TOOL:ShouldApplyColor()
	return self:GetClientNumber("color") == 1
end

function TOOL:ShouldApplyRendermode()
	return self:GetClientNumber("rendermode") == 1
end

function TOOL:ShouldApplyPhysicalProperties()
	return self:GetClientNumber("physprop") == 1
end

function TOOL:ApplyMaterial(ent, material)
	if !self:ShouldApplyMaterial() then return end
	ent:SetMaterial(material)
end

function TOOL:ApplyColor(ent, color)
	if !self:ShouldApplyColor() then return end
	ent:SetColor(color)
end

function TOOL:ApplyRendermode(ent, rendermode)
	if !self:ShouldApplyRendermode() then return end
	ent:SetRenderMode(rendermode)
end

function TOOL:ApplyFreeze(ply, ent)
	local phys = ent:GetPhysicsObject()
	if IsValid(phys) then
		ply:AddFrozenPhysicsObject(ent, phys)
		phys:EnableMotion(false)
	end
end

function TOOL:ApplyPhysicalProperties(original, new, boneID, properties)
	if !self:ShouldApplyPhysicalProperties() then return end
	if boneID then
		construct.SetPhysProp(nil, new, boneID, nil, properties)
	end
	local old_phys = original:GetPhysicsObject()
	local new_phys = new:GetPhysicsObject()
	if !IsValid(old_phys) or !IsValid(new_phys) then return end
	new_phys:SetMass(old_phys:GetMass())
	new:SetCollisionGroup(original:GetCollisionGroup())
end

function TOOL:GetDelay()
	return GetConVar("stacker_delay"):GetInt()
end

function TOOL:ReleaseGhostEntity()
	self:ReleaseGhostStack()
end

function TOOL:LeftClick(trace)
	local ent = trace.Entity
	if (!IsValid(ent) or ent:GetClass() != "prop_physics") then return false end
	if CLIENT then return true end
	local count = self:GetCount()
	if (count <= 0) then return false end
	if (self:GetOwner().LastStackTime and self:GetOwner().LastStackTime + self:GetDelay() > CurTime()) then self:GetOwner():PrintMessage(HUD_PRINTTALK, "Bitte benutze den Stacker nicht zu hastig!") return false end
	self:GetOwner().LastStackTime = CurTime()
	local stack_dir = self:GetDirection()
	local stack_mode = self:GetStackerMode()
	local stack_off = self:GetOffsetVector()
	local stack_rot = self:GetRotateAngle()
	local stack_rel = self:ShouldStackRelative()
	local stay_in_world = GetConVar("stacker_stayinworld"):GetBool()
	local ply = self:GetOwner()
	local ent_pos = ent:GetPos()
	local ent_ang = ent:GetAngles()
	local ent_mod = ent:GetModel()
	local ent_skin = ent:GetSkin()
	local ent_mat = ent:GetMaterial()
	local ent_col = ent:GetColor()
	local ent_render = ent:GetRenderMode()
	local phys_mat = ent:GetPhysicsObject():GetMaterial()
	local phys_grav = ent:GetPhysicsObject():IsGravityEnabled()
	local new_ent
	local direction, offset
	local distance = GetDistance(stack_mode, stack_dir, ent)
	undo.Create("Stacker")
		for i = 1, count do
			if !self:GetSWEP():CheckLimit("props") then break end
			if (hook.Run("PlayerSpawnProp", self:GetOwner(), ent_mod) == false) then break end
			if (i == 1 or (stack_mode == MODE_PROP and stack_rel)) then
				direction = GetDirection(stack_mode, stack_dir, ent_ang)
				offset = GetOffset(stack_mode, stack_dir, ent_ang, stack_off)
			end
			ent_pos = ent_pos + (direction * distance) + offset
			RotateAngle(stack_mode, stack_dir, ent_ang, stack_rot)
			if stay_in_world and !util.IsInWorld(ent_pos) then ply:PrintMessage(HUD_PRINTTALK, "Gestapelte Props dürfen nicht außerhalb der Map platziert werden!") break end
			new_ent = ents.Create("prop_physics")
			if !IsValid(new_ent) then break end
			new_ent:SetModel(ent_mod)
			new_ent:SetPos(ent_pos)
			new_ent:SetAngles(ent_ang)
			new_ent:SetSkin(ent_skin)
			new_ent:Spawn()
			new_ent:Activate()
			self:ApplyMaterial(new_ent, ent_mat)
			self:ApplyColor(new_ent, ent_col)
			self:ApplyRendermode(new_ent, ent_render)
			self:ApplyFreeze(ply, new_ent)
			self:ApplyPhysicalProperties(ent, new_ent, trace.PhysicsBone, {GravityToggle = phys_grav, Material = phys_mat})
			undo.AddEntity(new_ent)
			ply:AddCleanup("props", new_ent)
			hook.Run("PlayerSpawnedProp", ply, ent_mod, new_ent)
			hook.Run("StackerEntity", new_ent, ply)
		end
	undo.SetPlayer(ply)
	undo.Finish()
	return true
end

function TOOL:RightClick()
	if CLIENT then return false end
	if (self.NextSwitch or 0) > CurTime() then return end
	self.NextSwitch = CurTime() + 0.2
	local dir = self:GetClientNumber("dir") + 1
	if dir <= 0 or dir > 6 then
		dir = 1
	end
	local ply = self:GetOwner()
	ply:ConCommand("stacker_dir "..dir)
	local translate = dir == 1 and "nach oben" or dir == 2 and "nach unten" or dir == 3 and "nach vorne" or dir == 4 and "nach hinten" or dir == 5 and "nach rechts" or dir == 6 and "nach links"
	ply:ChatPrint("Stapelrichtung auf "..translate.." ("..dir..") geändert.")
	return false
end

function TOOL:CreateGhostStack(ent)
	if !IsFirstTimePredicted() then return end

	self:ReleaseGhostStack()

	local count = self:GetCount()
	local ent_model = ent:GetModel()
	local ent_pos = ent:GetPos()
	local ghoststack = {}

	for i = 1, count do
		local ghost = ents.CreateClientProp(ent_model)
		if !IsValid(ghost) then continue end
		ghost:SetPos(ent_pos)
		ghost:Spawn()
		ghost:PhysicsDestroy()
		ghost:SetMoveType(MOVETYPE_NONE)
		ghost:SetNotSolid(true)
		ghost:SetRenderMode(RENDERMODE_TRANSCOLOR)
		ghost:SetColor(TRANSPARENT)
		table.insert(ghoststack, ghost)
	end

	SetGhostStack(ghoststack)
	self:UpdateGhostStack(ent)

	return true
end

function TOOL:ReleaseGhostStack()
	local ghoststack = GetGhostStack()
	if table.IsEmpty(ghoststack) then return end

	for k, v in pairs(ghoststack) do
		if IsValid(v) then
			v:Remove()
		end
	end

	ghoststack = {}
end

function TOOL:CheckGhostStack()
	local ghoststack = GetGhostStack()

	for _, v in pairs(ghoststack) do
		if !IsValid(v) then
			return false
		end
	end

	return true
end

function TOOL:UpdateGhostStack(ent)
	local ghoststack = GetGhostStack()
	local cnt = table.Count(ghoststack)

	if cnt != self:GetCount() and IsFirstTimePredicted() then
		self:CreateGhostStack(ent)
	end

	local stack_mode = self:GetStackerMode()
	local stack_dir = self:GetDirection()
	local stack_off = self:GetOffsetVector()
	local stack_rot = self:GetRotateAngle()
	local stack_rel = self:ShouldStackRelative()
	local apply_mat = self:ShouldApplyMaterial()
	local apply_col = self:ShouldApplyColor()
	local last_ent = ent
	local ent_pos = last_ent:GetPos()
	local ent_ang = last_ent:GetAngles()
	local ent_mat = ent:GetMaterial()
	local ent_col = ent:GetColor()

	ent_col.a = 150
	local direction, offset
	local distance = GetDistance(stack_mode, stack_dir, ent)
	local first = true

	for k, v in pairs(ghoststack) do
		if !IsValid(v) then
			ghoststack[k] = nil
			continue
		end
		if (first or (stack_mode == MODE_PROP and stack_rel)) then
			direction = GetDirection(stack_mode, stack_dir, ent_ang)
			offset = GetOffset(stack_mode, stack_dir, ent_ang, stack_off)
		end

		first = false

		ent_pos = ent_pos + (direction * distance) + offset
		RotateAngle(stack_mode, stack_dir, ent_ang, stack_rot)
		v:SetPos(ent_pos)
		v:SetAngles(ent_ang)
		v:SetMaterial((apply_mat and ent_mat) or "")

		last_ent = v
	end
end

function TOOL:Think()
	if SERVER then return end

	local ply = self:GetOwner()
	if IsFirstTimePredicted() and ply:KeyPressed(IN_RELOAD) then
		RunConsoleCommand("stacker_resetoffsets")
		ply:ChatPrint("Alle Abstände wurden zurückgesetzt.")
	end

	local ent = ply:GetEyeTrace().Entity
	if IsValid(ent) and ent:GetClass() == "prop_physics" then
		local tb = self.GetTable and self:GetTable() or self
		tb.CurrentEnt = ent
		if tb.CurrentEnt == tb.LastEnt then
			if self:CheckGhostStack() then
				self:UpdateGhostStack(tb.CurrentEnt)
			else
				self:ReleaseGhostStack()
				tb.LastEnt = nil
			end
		else
			if self:CreateGhostStack(tb.CurrentEnt) then
				tb.LastEnt = tb.CurrentEnt 
			end
		end
	else
		self:ReleaseGhostStack()
		self.LastEnt = nil
	end
end

local ConVarsDefault = TOOL:BuildConVarList()
function TOOL.BuildCPanel(cpanel)
	cpanel:AddControl("Header", {Text = "#tool.stacker.name", Description = "#tool.stacker.desc"})
	cpanel:AddControl("ComboBox", {MenuButton = 1, Folder = "stacker", Options = {["#preset.default"] = ConVarsDefault}, CVars = table.GetKeys(ConVarsDefault)})
	local params = {Label = "Stapeln relativ zu:", MenuButton = "0", Options = {}}
	params.Options["Welt"] = {stacker_mode = "1"}
	params.Options["Prop"]  = {stacker_mode = "2"}
	cpanel:AddControl("ComboBox", params)
	local params = {Label = "Stapelrichtung", MenuButton = "0", Options = {}}
	params.Options["Nach oben"] = {stacker_dir = DIRECTION_UP}
	params.Options["Nach unten"] = {stacker_dir = DIRECTION_DOWN}
	params.Options["Nach vorne"] = {stacker_dir = DIRECTION_FRONT}
	params.Options["Nach hinten"] = {stacker_dir = DIRECTION_BACK}
	params.Options["Nach rechts"] = {stacker_dir = DIRECTION_RIGHT}
	params.Options["Nach links"] = {stacker_dir = DIRECTION_LEFT}
	cpanel:AddControl("ComboBox", params)
	cpanel:AddControl("Slider", {Label = "Stapelanzahl:", Type = "Integer", Min = 1, Max = GetConVar("stacker_max_count"):GetInt(), Command = "stacker_count"})
	cpanel:AddControl("Button", {Label = "Abstände und Rotationen zurücksetzen", Command = "stacker_resetoffsets", Text = "Zurücksetzung"})
	cpanel:AddControl("Slider", {Label = "Abstand: X (links/rechts)", Type = "Float", Min = - GetConVar("stacker_max_offsetx"):GetFloat(), Max = GetConVar("stacker_max_offsetx"):GetFloat(), Value = 0, Command = "stacker_offsetx"})
	cpanel:AddControl("Slider", {Label = "Abstand: Y (vorwärts/rückwärts)", Type = "Float", Min = - GetConVar("stacker_max_offsety"):GetFloat(), Max = GetConVar("stacker_max_offsety"):GetFloat(), Value = 0, Command = "stacker_offsety"})
	cpanel:AddControl("Slider", {Label = "Abstand: Z (hoch/runter)", Type = "Float", Min = - GetConVar("stacker_max_offsetz"):GetFloat(), Max = GetConVar("stacker_max_offsetz"):GetFloat(), Value = 0, Command = "stacker_offsetz"})
	cpanel:AddControl("Slider", {Label = "Rotation: Neigung", Type = "Float", Min = -360,  Max = 360, Value = 0, Command = "stacker_rotp"})
	cpanel:AddControl("Slider", {Label = "Rotation: Gierung", Type = "Float", Min = -360,  Max = 360, Value = 0, Command = "stacker_roty"})
	cpanel:AddControl("Slider", {Label = "Rotation: Rolle", Type = "Float", Min = -360,  Max = 360, Value = 0, Command = "stacker_rotr"})
	cpanel:AddControl("Checkbox", {Label = "Stapeln in Bezug auf neue Rotation", Command = "stacker_recalc"})
	cpanel:AddControl("Checkbox", {Label = "Physikalische Eigenschaften annehmen", Command = "stacker_physprop"})
	cpanel:AddControl("Checkbox", {Label = "Material annehmen", Command = "stacker_material"})
	cpanel:AddControl("Checkbox", {Label = "Farbe annehmen", Command = "stacker_color"})
	cpanel:AddControl("Checkbox", {Label = "Transparenz annehmen", Command = "stacker_rendermode"})
end

if CLIENT then
	local red = Color(255, 0, 0)
	local green = Color(0, 255, 0)
	local blue = Color(0, 125, 255)
	local black = Color(0, 0, 0)

	surface.CreateFont("stacker_mode", {font = "Arial", size = 24, weight = 700, antialias = true})

	local local_ply, ent
	local function DrawDirections(depth, sky)
		if depthy or sky then return end
		local_ply = local_ply or LocalPlayer()
		local wep = local_ply:GetActiveWeapon()
		if !wep:IsValid() or wep:GetClass() != "gmod_tool" or wep:GetMode() != "stacker" then return end
		ent = local_ply:GetEyeTrace().Entity
		if !IsValid(ent) then return end
		local class = ent:GetClass()
		if class != "prop_physics" and class != "prop_physics_multiplayer" then return end
		local pos = ent:GetPos()
		local f = ent:GetForward()
		local r = ent:GetRight()
		local u = ent:GetUp()
		render.DrawLine(pos, pos + (f * 50), red, false)
		render.DrawLine(pos + (f * 50) - f * 2.5 + Vector(0, 0, 2.5), pos + (f * 50), red, false)
		render.DrawLine(pos + (f * 50) - f * 2.5 - Vector(0, 0, 2.5), pos + (f * 50), red, false)
		render.DrawLine(pos + Vector(0, 0, 0.05), pos + (f * 50) + Vector(0, 0, 0.05), red, false)
		render.DrawLine(pos + Vector(0, 0, -0.05), pos + (f * 50) + Vector(0, 0, -0.05), red, false)
		render.DrawLine(pos, pos + (r * 50), green, false)
		render.DrawLine(pos + (r * 50) - r * 2.5 + f * 2.5, pos + (r * 50), green, false)
		render.DrawLine(pos + (r * 50) - r * 2.5 - f * 2.5, pos + (r * 50), green, false)
		render.DrawLine(pos + Vector(0, 0, 0.05), pos + (r * 50) + Vector(0, 0, 0.05), green, false)
		render.DrawLine(pos + Vector(0, 0, -0.05), pos + (r * 50) + Vector(0, 0, -0.05), green, false)
		render.DrawLine(pos, pos + (u * 50), blue, false)
		render.DrawLine(pos + (u * 50) - u * 2.5 + r * 2.5, pos + (u * 50), blue, false)
		render.DrawLine(pos + (u * 50) - u * 2.5 - r * 2.5, pos + (u * 50), blue, false)
		render.DrawLine(pos + Vector(0.05, 0, 0), pos + (u * 50) + Vector(0.05, 0, 0), blue, false)
		render.DrawLine(pos + Vector(-0.05, 0, 0), pos + (u * 50) + Vector(-0.05, 0, 0), blue, false)
		local fs = (pos + f * 50 - u * 5):ToScreen()
		local rs = (pos + r * 50 - u * 5):ToScreen()
		local us = (pos + u * 55):ToScreen()
		cam.Start2D()
			draw.SimpleTextOutlined("Vorwärts", "stacker_mode", fs.x, fs.y, red, 0, 0, 1, black)
			draw.SimpleTextOutlined("Rechts", "stacker_mode", rs.x, rs.y, green, 0, 0, 1, black)
			draw.SimpleTextOutlined("Hoch", "stacker_mode", us.x, us.y, blue, 1, 0, 1, black)
		cam.End2D()
	end
	hook.Add("PostDrawTranslucentRenderables", "Stacker_DrawDirections", DrawDirections)
end