--
-- FS19 - Delimber
-- @author:    	kenny456 (kenny456@seznam.cz)
-- @history:	v1.0.0.0 - 2021-11-16 - first release
--
Delimber = {}
Delimber.confDir = getUserProfileAppPath().. "modsSettings/Delimber/"
Delimber.modDirectory = g_currentModDirectory
local modName = g_currentModName
Delimber.showHelp = true

function Delimber.prerequisitesPresent(specializations)
	return true
end
function Delimber.initSpecialization()
    local schema = Vehicle.xmlSchema
    schema:setXMLSpecializationType("Delimber")

    EffectManager.registerEffectXMLPaths(schema, "vehicle.delimber.cutEffects")
    EffectManager.registerEffectXMLPaths(schema, "vehicle.delimber.delimbEffects")
    Dashboard.registerDashboardXMLPaths(schema, "vehicle.delimber.dashboards", "lengthBottom | lengthTop | diameter")
    schema:setXMLSpecializationType()

    local schemaSavegame = Vehicle.xmlSchemaSavegame
end

function Delimber.registerOverwrittenFunctions(vehicleType)
end
function Delimber.registerFunctions(vehicleType)
	SpecializationUtil.registerFunction(vehicleType, "delimberCutTree", Delimber.delimberCutTree)
	SpecializationUtil.registerFunction(vehicleType, "delimberReleaseGrabRotation", Delimber.delimberReleaseGrabRotation)
	SpecializationUtil.registerFunction(vehicleType, "getCanDelimb", Delimber.getCanDelimb)
end
function Delimber:onRegisterActionEvents(isActiveForInput, isActiveForInputIgnoreSelection)
	local spec = self.spec_delimber
	if not spec.modInitialized or not spec.modAllowed then
		return
	end
	
	if spec.event_IDs == nil then
		spec.event_IDs = {}
	else
		self:clearActionEventsTable(spec.event_IDs)
	end
	if self:getIsActiveForInput() or (self.getIscontrolled ~= nil and self:getIsControlled()) then
		if g_dedicatedServerInfo ~= nil then
			return
		end
		local actions = { InputAction.DELIMBER_CUT_TREE, InputAction.DELIMBER_RELEASE_GRAB_ROTATION }
		for _,actionName in pairs(actions) do
			local always = (actionName == InputAction.WORKRPM_MOVE_HUD_TRIGGER) and true or false
			local _, eventID = g_inputBinding:registerActionEvent(actionName, self, Delimber.actionCallback, true, true, always, true)
			spec.event_IDs[actionName] = eventID
			if g_inputBinding ~= nil and g_inputBinding.events ~= nil and g_inputBinding.events[eventID] ~= nil then
				if actionName == 'something with lower priority' then
					g_inputBinding:setActionEventTextPriority(eventID, GS_PRIO_NORMAL)
				else
					g_inputBinding:setActionEventTextPriority(eventID, GS_PRIO_VERY_HIGH)-----------------------------	ZKUSIT NIZSI PRIORITU
				end
				g_inputBinding:setActionEventTextVisibility(eventID, Delimber.showHelp)
			end
			local colliding = false
			_, colliding, _ = g_inputBinding:checkEventCollision(actionName)
			if colliding then
				if g_inputBinding.nameActions[actionName].bindings[1] ~= nil then
					if g_inputBinding.nameActions[actionName].bindings[1].inputString ~= nil then
						print(string.format('Warning: Delimber got a colliding input action: %s', actionName)..' ('..g_inputBinding.nameActions[actionName].bindings[1].inputString..'). You can remap it in controls settings')
					end
				else
					print(string.format('Warning: Delimber got a colliding input action: %s', actionName))
				end
			end
		end
	end
end
function Delimber.registerEventListeners(vehicleType)
	for _,n in pairs( { "onLoad", "onPostLoad", "onDelete", "saveToXMLFile", "onUpdate", "onUpdateTick", "onDraw", "onReadStream", "onWriteStream", "onRegisterActionEvents", "delimberCutTree", "delimberReleaseGrabRotation" } ) do
		SpecializationUtil.registerEventListener(vehicleType, n, Delimber)
	end
end
function Delimber:onLoad(savegame)
	self.spec_delimber = {}
	local spec = self.spec_delimber
	
	local baseKey = "vehicle.delimber"
	spec.cutAnimation = {}
    spec.cutAnimation.name = getXMLString(self.xmlFile.handle, baseKey..".cutAnimation#name")
    spec.cutAnimation.speedScale = Utils.getNoNil(getXMLFloat(self.xmlFile.handle, baseKey..".cutAnimation#speedScale"), 1)
    spec.cutAnimation.cutTime = Utils.getNoNil(getXMLFloat(self.xmlFile.handle, baseKey..".cutAnimation#cutTime"), 0.8)
	spec.samples = {}
    spec.samples.cut    = g_soundManager:loadSampleFromXML(self.xmlFile.handle, baseKey..".sounds", "cut", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self)
    spec.samples.delimb = g_soundManager:loadSampleFromXML(self.xmlFile.handle, baseKey..".sounds", "delimb", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self)
	spec.samples.start = g_soundManager:loadSampleFromXML(self.xmlFile.handle, baseKey..".sounds", "start", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self)
    spec.samples.stop  = g_soundManager:loadSampleFromXML(self.xmlFile.handle, baseKey..".sounds", "stop", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self)
    spec.samples.work  = g_soundManager:loadSampleFromXML(self.xmlFile.handle, baseKey..".sounds", "work", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self)
    spec.isCutSamplePlaying = false
    spec.isDelimbSamplePlaying = false
	spec.cutEffects = g_effectManager:loadEffect(self.xmlFile, baseKey..".cutEffects", self.components, self, self.i3dMappings)
	spec.delimbEffects = g_effectManager:loadEffect(self.xmlFile, baseKey..".delimbEffects", self.components, self, self.i3dMappings)
	spec.delimbNode = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile.handle, baseKey..".delimbNode#node"), self.i3dMappings)
	spec.delimbNodeHead = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile.handle, baseKey..".delimbNode#delimbNodeHead"), self.i3dMappings)
	spec.delimbSizeX = Utils.getNoNil(getXMLFloat(self.xmlFile.handle, baseKey..".delimbNode#sizeX"), 0.1)
    spec.delimbSizeY = Utils.getNoNil(getXMLFloat(self.xmlFile.handle, baseKey..".delimbNode#sizeY"), 1)
    spec.delimbSizeZ = Utils.getNoNil(getXMLFloat(self.xmlFile.handle, baseKey..".delimbNode#sizeZ"), 1)
    spec.effectTimer = Utils.getNoNil(getXMLFloat(self.xmlFile.handle, baseKey..".delimbNode#effectTimer"), 1500)
    spec.delimbClawsMovingTool = Utils.getNoNil(getXMLInt(self.xmlFile.handle, baseKey..".delimbNode#delimbClawsMovingTool"), 0)
    spec.clawsRotationMovingTool = Utils.getNoNil(getXMLInt(self.xmlFile.handle, baseKey..".delimbNode#clawsRotationMovingTool"), 0)
	spec.cutNode = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile.handle, baseKey .. ".cutNode#node"), self.i3dMappings)
	spec.cutLengthInfo = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile.handle, baseKey .. ".cutNode#cutLengthInfo"), self.i3dMappings)
    spec.cutSizeY = Utils.getNoNil(getXMLFloat(self.xmlFile.handle, baseKey .. ".cutNode#sizeY"), 1)
    spec.cutSizeZ = Utils.getNoNil(getXMLFloat(self.xmlFile.handle, baseKey .. ".cutNode#sizeZ"), 1)
    spec.lengthAboveThreshold = Utils.getNoNil(getXMLFloat(self.xmlFile.handle, baseKey .. ".cutNode#lengthAboveThreshold"), 0.3)
    spec.lengthBelowThreshold = Utils.getNoNil(getXMLFloat(self.xmlFile.handle, baseKey .. ".cutNode#lengthBelowThreshold"), 0.3)
    spec.cutTimerDuration = Utils.getNoNil(getXMLFloat(self.xmlFile.handle, baseKey .. ".cutNode#timer"), 0.1)*1000
    spec.delimbSplitShape = nil
    spec.curSplitShape = nil
    spec.cutTimer = -1
    spec.grabRotationReleased = false
	spec.isDelimbing = false
	spec.isDelimbingForSound = false
	spec.delimbed = false
	spec.timerDelimbing = 0
	spec.lengthRemBottom = 0
	spec.lengthRemTop = 0
	spec.lastTreeDiameter = 0
	spec.massOrig = getMass(self.rootNode)
	spec.massUnfolded = Utils.getNoNil(getXMLFloat(self.xmlFile.handle, baseKey .. ".delimbNode#massUnfolded"), 50)
	spec.infoText = ''
	spec.referencePoint = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile.handle, baseKey..".delimbNode#referencePoint"), self.i3dMappings)
	spec.referenceFrame = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile.handle, baseKey..".delimbNode#referenceFrame"), self.i3dMappings)

	if self.loadDashboardsFromXML ~= nil then
        self:loadDashboardsFromXML(self.xmlFile, "vehicle.delimber.dashboards", {valueTypeToLoad = "lengthBottom",
                                                                                      valueObject = spec,
                                                                                      valueFunc = function(spec)
                                                                                          return spec.lengthRemBottom * 10
                                                                                      end})
        self:loadDashboardsFromXML(self.xmlFile, "vehicle.delimber.dashboards", {valueTypeToLoad = "lengthTop",
                                                                                      valueObject = spec,
                                                                                      valueFunc = function(spec)
                                                                                          return spec.lengthRemTop * 10
                                                                                      end})
        self:loadDashboardsFromXML(self.xmlFile, "vehicle.delimber.dashboards", {valueTypeToLoad = "diameter",
                                                                                      valueObject = spec,
                                                                                      valueFunc = function(spec)
                                                                                          return spec.lastTreeDiameter * 1000
                                                                                      end})
    end
end
function Delimber:onPostLoad(savegame)
	local spec = self.spec_delimber

	spec.modInitialized = true
	spec.modAllowed = true
	if not spec.modInitialized then
		return
	else
	end
	spec.modActive = true
	if savegame ~= nil then
		local xmlFile = savegame.xmlFile
		local key = savegame.key.."."..modName..".Delimber"
		spec.grabRotationReleased = Utils.getNoNil(getXMLBool(xmlFile.handle, key.."#grabRotationReleased"), spec.grabRotationReleased)
	end
end
function Delimber:onDelete()
	local spec = self.spec_delimber
	if not spec.modInitialized or not spec.modAllowed then
		return
	end
end
function Delimber:saveToXMLFile(xmlFile, key)
	local spec = self.spec_delimber
	if not spec.modInitialized or not spec.modAllowed then
		return
	end
	
	setXMLBool(xmlFile.handle, key.."#grabRotationReleased", spec.grabRotationReleased)
end
function Delimber:onUpdate(dt)
	local spec = self.spec_delimber
	if not spec.modInitialized or not spec.modAllowed then
		return
	end
	
	--spec.infoText = ''
	if spec.delimbSplitShape ~= nil then
        if not entityExists(spec.delimbSplitShape) then
            spec.delimbSplitShape = nil
		end
	end
	if spec.shapeInHead ~= nil then
        if not entityExists(spec.shapeInHead) then
            spec.shapeInHead = nil
		end
	end
	if spec.delimbSplitShape ~= nil and spec.shapeInHead ~= nil then
		if spec.delimbSplitShape == spec.shapeInHead then
			spec.isDelimbing = true
		else
			spec.isDelimbing = false
		end
	else
		spec.isDelimbing = false
	end
	if self.isServer then
		if spec.clawsRotationMovingTool ~= nil and spec.clawsRotationMovingTool ~= 0 then
			if self.spec_cylindered.movingTools[spec.clawsRotationMovingTool] ~= nil then
				local x,y,z = getWorldRotation(spec.referenceFrame)
				local a,b,c = worldRotationToLocal(spec.referencePoint, x,y,z)
				local x,y,z = getRotation(self.spec_cylindered.movingTools[spec.clawsRotationMovingTool].node)
				if spec.grabRotationReleased and spec.isDelimbing and not self.spec_cylindered.movingTools[spec.clawsRotationMovingTool].isDirty then
					local moved = false
					if a > 0.05 then
						y = y + 0.01
						moved = true
					elseif a < -0.01 then
						y = y - 0.01
						moved = true
					end
					if moved then
						self.spec_cylindered.movingTools[spec.clawsRotationMovingTool].curRot[2] = y
						setRotation(self.spec_cylindered.movingTools[spec.clawsRotationMovingTool].node, x,y,z)
						Cylindered.setDirty(self, self.spec_cylindered.movingTools[spec.clawsRotationMovingTool])
					end
					self.componentJoints[1].rotLimitSpring[1] = 10
					setJointRotationLimitSpring(self.componentJoints[1].jointIndex, 0, self.componentJoints[1].rotLimitSpring[1], self.componentJoints[1].rotLimitDamping[1])
				else
					self.componentJoints[1].rotLimitSpring[1] = 0
					setJointRotationLimitSpring(self.componentJoints[1].jointIndex, 0, self.componentJoints[1].rotLimitSpring[1], self.componentJoints[1].rotLimitDamping[1])
				end
			end
		end
	
		if self:getIsUnfolded() ~= nil and self:getIsUnfolded() then
			local mass = getMass(self.rootNode)
			if mass < spec.massUnfolded then
				setMass(self.rootNode, spec.massUnfolded)
			end
		else
			local mass = getMass(self.rootNode)
			if mass > spec.massOrig then
				setMass(self.rootNode, spec.massOrig)
			end
		end
		if spec.delimbNode ~= nil and spec.delimbSplitShape ~= nil then
			if self:getCanDelimb() then
				local x,y,z = getWorldTranslation(spec.delimbNode)
				local nx,ny,nz = localDirectionToWorld(spec.delimbNode, 1,0,0)
				local yx,yy,yz = localDirectionToWorld(spec.delimbNode, 0,1,0)
				spec.delimbed = removeSplitShapeAttachments(spec.delimbSplitShape, x,y,z, nx,ny,nz, yx,yy,yz, spec.delimbSizeX, spec.delimbSizeY, spec.delimbSizeZ)
				if spec.delimbed then
					DelimberDelimbEvent.sendEvent(self, spec.delimbed, noEventSend)
				end
			end
		end
		if spec.cutNode ~= nil and spec.cutAnimation.name ~= nil then
			if self:getIsAnimationPlaying(spec.cutAnimation.name) then
				if spec.curSplitShape ~= nil then
					if not entityExists(spec.curSplitShape) then
						spec.curSplitShape = nil
						if g_server ~= nil then
							spec.cutTimer = -1
						end
					end
				end
				if spec.curSplitShape ~= nil then
					if spec.cutTimer > 0 then
						spec.cutTimer = math.max(spec.cutTimer - dt, 0)
					end
					-- cut
					if  spec.cutTimer == 0 then
						spec.cutTimer = -1
						local x,y,z = getWorldTranslation(spec.cutNode)
						local nx,ny,nz = localDirectionToWorld(spec.cutNode, 1,0,0)
						local yx,yy,yz = localDirectionToWorld(spec.cutNode, 0,1,0)
						ChainsawUtil.cutSplitShape(spec.curSplitShape, x,y,z, nx,ny,nz, yx,yy,yz, spec.cutSizeY, spec.cutSizeZ, self:getActiveFarm())
						spec.curSplitShape = nil
					end
				end
			end
		end
    end
	if spec.delimbed then
		spec.isDelimbingForSound = true
	end
	if spec.isDelimbingForSound then
		spec.timerDelimbing = spec.timerDelimbing + dt
		if spec.timerDelimbing >= spec.effectTimer then
			spec.isDelimbingForSound = false
			spec.timerDelimbing = 0
			spec.delimbed = false
		end
	end
	--[[spec.infoText = spec.infoText .. 'delimbSplitShape - '..(spec.delimbSplitShape ~= nil and spec.delimbSplitShape or 'nil')..'\n'
	spec.infoText = spec.infoText .. 'shapeInHead - '..(spec.shapeInHead ~= nil and spec.shapeInHead or 'nil')..'\n'
	spec.infoText = spec.infoText .. 'curSplitShape - '..(spec.curSplitShape ~= nil and spec.curSplitShape or 'nil')..'\n'
	spec.infoText = spec.infoText .. 'cutTimer - '..spec.cutTimer..'\n'
	spec.infoText = spec.infoText .. 'timerDelimbing - '..spec.timerDelimbing..'\n'
	spec.infoText = spec.infoText .. 'delimbed - '..tostring(spec.delimbed)..'\n'
	spec.infoText = spec.infoText .. 'isDelimbing - '..tostring(spec.isDelimbing)..'\n'
	spec.infoText = spec.infoText .. 'isDelimbingForSound - '..tostring(spec.isDelimbingForSound)..'\n'
	spec.infoText = spec.infoText .. 'getCanDelimb - '..tostring(self:getCanDelimb())..'\n'
	spec.infoText = spec.infoText .. 'grabRotationReleased - '..tostring(spec.grabRotationReleased)..'\n'
	spec.infoText = spec.infoText .. 'movingTools[1] - '..tostring(self.spec_cylindered.movingTools[1].curRot[2])..'\n'
	spec.infoText = spec.infoText .. 'clawsRotationMovingTool - '..tostring(self.spec_cylindered.movingTools[spec.clawsRotationMovingTool].curRot[2])..'\n'
	spec.infoText = spec.infoText .. 'movingTools[5].rotSpeed - '..tostring(self.spec_cylindered.movingTools[5].rotSpeed)..'\n'
	spec.infoText = spec.infoText .. 'movingTools[5].lastRotSpeed - '..tostring(self.spec_cylindered.movingTools[5].lastRotSpeed)..'\n'
	spec.infoText = spec.infoText .. 'movingTools[5].move - '..tostring(self.spec_cylindered.movingTools[5].move)..'\n'
	spec.infoText = spec.infoText .. 'diameter - '..tostring(spec.lastTreeDiameter)..'\n'
	spec.infoText = spec.infoText .. 'item - '..tostring(spec.item)..'\n'
	spec.infoText = spec.infoText .. 'suspTravel - '..string.format('%.3f', self.spec_wheels.wheels[1].suspTravel)..'\n'
	spec.infoText = spec.infoText .. 'spring - '..string.format('%.0f', self.spec_wheels.wheels[1].spring / 10) ..'\n'
	spec.infoText = spec.infoText .. 'massRoot - '..string.format('%.3f', getMass(self.rootNode)) ..'\n']]
	if self.isClient then
		if spec.cutTimer > 0 then
            g_effectManager:setFillType(spec.cutEffects, FillType.WOODCHIPS)
            g_effectManager:startEffects(spec.cutEffects)
            if not g_soundManager:getIsSamplePlaying(spec.samples.cut) then
                g_soundManager:playSample(spec.samples.cut)
            end
        else
            g_effectManager:stopEffects(spec.cutEffects)
            if g_soundManager:getIsSamplePlaying(spec.samples.cut) then
                g_soundManager:stopSample(spec.samples.cut)
            end
        end
        -- cut
        if spec.cutAnimation.name ~= nil then
            if self:getIsAnimationPlaying(spec.cutAnimation.name) and self:getAnimationTime(spec.cutAnimation.name) < spec.cutAnimation.cutTime then
                if not spec.isCutSamplePlaying then
                    spec.isCutSamplePlaying = true
                end
            else
                if spec.isCutSamplePlaying then
                    g_soundManager:stopSample(spec.samples.work)
					g_soundManager:playSample(spec.samples.stop)
                    spec.isCutSamplePlaying = false
                end
            end
        end
        -- delimb
        if spec.isDelimbingForSound then
            if not spec.isDelimbSamplePlaying then
                g_soundManager:playSample(spec.samples.delimb)
                spec.isDelimbSamplePlaying = true
            end
            g_effectManager:setFillType(spec.delimbEffects, FillType.WOODCHIPS)
            g_effectManager:startEffects(spec.delimbEffects)
        else
            if spec.isDelimbSamplePlaying then
                g_soundManager:stopSample(spec.samples.delimb)
                spec.isDelimbSamplePlaying = false
            end
            g_effectManager:stopEffects(spec.delimbEffects)
        end
		
		if self:getIsActiveForInput() or (self.getIscontrolled ~= nil and self:getIsControlled()) then
			if spec.event_IDs ~= nil and g_dedicatedServerInfo == nil then
				for actionName,eventID in pairs(spec.event_IDs) do
					if actionName == InputAction.DELIMBER_CUT_TREE then
						local can = false
						if spec.cutAnimation.name ~= nil and not self:getIsAnimationPlaying(spec.cutAnimation.name) then can = true end
						g_inputBinding:setActionEventActive(eventID, can)
						g_inputBinding:setActionEventText(eventID, g_i18n:getText('input_DELIMBER_CUT_TREE'))
					elseif actionName == InputAction.DELIMBER_RELEASE_GRAB_ROTATION then
						g_inputBinding:setActionEventActive(eventID, (spec.clawsRotationMovingTool ~= nil and spec.clawsRotationMovingTool ~= 0) and true or false)
						g_inputBinding:setActionEventText(eventID, spec.grabRotationReleased and g_i18n:getText('DELIMBER_RELEASE_GRAB_ROTATION_ON') or g_i18n:getText('DELIMBER_RELEASE_GRAB_ROTATION_OFF'))
					end
				end
			end
			if spec.isDelimbing and spec.shapeInHead ~= nil and spec.cutLengthInfo ~= nil then
				local x,y,z = getWorldTranslation(spec.cutLengthInfo)
				local nx,ny,nz = localDirectionToWorld(spec.cutLengthInfo, 0,0,1)
				local _, lengthRemTop = getSplitShapePlaneExtents(spec.shapeInHead, x,y,z, nx,ny,nz)
				local nx,ny,nz = localDirectionToWorld(spec.cutLengthInfo, 0,0,-1)
				local _, lengthRemBottom = getSplitShapePlaneExtents(spec.shapeInHead, x,y,z, nx,ny,nz)
				if lengthRemTop ~=  nil and lengthRemBottom ~= nil then
					spec.lengthRemBottom = lengthRemBottom
					if lengthRemTop < 0 then
						spec.lengthRemTop = 0
					else
						spec.lengthRemTop = lengthRemTop
					end
					g_currentMission:addExtraPrintText(g_i18n:getText('DELIMBER_INFO').." "..string.format('%.1f', spec.lengthRemBottom).." m ("..string.format('%.1f', spec.lengthRemTop).." m "..g_i18n:getText('DELIMBER_INFO2').."), d:"..string.format('%.0f', spec.lastTreeDiameter*1000)..' mm')
				end
				
			end
		end
    end
end
function Delimber:onUpdateTick(dt)
	local spec = self.spec_delimber
	
	if spec.delimbNode ~= nil then
        local x,y,z = getWorldTranslation(spec.delimbNode)
        local nx,ny,nz = localDirectionToWorld(spec.delimbNode, 1,0,0)
        local yx,yy,yz = localDirectionToWorld(spec.delimbNode, 0,1,0)
       -- if spec.delimbSplitShape == nil then
            local shape, minY, maxY, minZ, maxZ = findSplitShape(x,y,z, nx,ny,nz, yx,yy,yz, spec.delimbSizeY, spec.delimbSizeZ)
            if shape ~= 0 then
				spec.delimbSplitShape = shape
				spec.lastTreeDiameter = math.max(maxY-minY, maxZ-minZ)
			else
				spec.delimbSplitShape = nil
				spec.lengthRemBottom = 0
				spec.lengthRemTop = 0
				spec.lastTreeDiameter = 0
			end
		--end
	end
	if spec.delimbNodeHead ~= nil then
        local x,y,z = getWorldTranslation(spec.delimbNodeHead)
        local nx,ny,nz = localDirectionToWorld(spec.delimbNodeHead, 1,0,0)
        local yx,yy,yz = localDirectionToWorld(spec.delimbNodeHead, 0,1,0)
       -- if spec.shapeInHead == nil then
            local shape, _, _, _, _ = findSplitShape(x,y,z, nx,ny,nz, yx,yy,yz, spec.delimbSizeY, spec.delimbSizeZ)
            if shape ~= 0 then
				spec.shapeInHead = shape
			else
				spec.shapeInHead = nil
			end
		--end
	end
    if spec.cutNode ~= nil and spec.cutAnimation.name ~= nil then
        if self:getIsAnimationPlaying(spec.cutAnimation.name) then
            local x,y,z = getWorldTranslation(spec.cutNode)
            local nx,ny,nz = localDirectionToWorld(spec.cutNode, 1,0,0)
            local yx,yy,yz = localDirectionToWorld(spec.cutNode, 0,1,0)
            if spec.curSplitShape == nil then
                local shape, _, _, _, _ = findSplitShape(x,y,z, nx,ny,nz, yx,yy,yz, spec.cutSizeY, spec.cutSizeZ)
                if shape ~= 0 then
                   spec.curSplitShape = shape
                   spec.cutTimer = spec.cutTimerDuration
				end
            end
            if spec.curSplitShape ~= nil then
                local minY,maxY, minZ,maxZ = testSplitShape(spec.curSplitShape, x,y,z, nx,ny,nz, yx,yy,yz, spec.cutSizeY, spec.cutSizeZ)
                if minY == nil then
                    spec.curSplitShape = nil
                else
                    local cutTooLow = false
                    local _,y,_ = localToLocal(spec.cutNode, spec.curSplitShape, 0,minY,minZ)
                    cutTooLow = cutTooLow or y < 0.01
                    local _,y,_ = localToLocal(spec.cutNode, spec.curSplitShape, 0,minY,maxZ)
                    cutTooLow = cutTooLow or y < 0.01
                    local _,y,_ = localToLocal(spec.cutNode, spec.curSplitShape, 0,maxY,minZ)
                    cutTooLow = cutTooLow or y < 0.01
                    local _,y,_ = localToLocal(spec.cutNode, spec.curSplitShape, 0,maxY,maxZ)
                    cutTooLow = cutTooLow or y < 0.01
                    if cutTooLow then
                        spec.curSplitShape = nil
                    end
                end
            end
            if spec.curSplitShape ~= nil then
                local lenBelow, lenAbove = getSplitShapePlaneExtents(spec.curSplitShape, x,y,z, nx,ny,nz)
                if lenAbove < spec.lengthAboveThreshold or lenBelow < spec.lengthBelowThreshold then
                    spec.curSplitShape = nil
                end
            end
            if spec.curSplitShape == nil and spec.cutTimer > -1 then
                spec.cutTimer = -1
            end
        end
    end
end
function Delimber:delimberCutTree(noEventSend)
	local spec = self.spec_delimber
	
	if self.isClient then
		g_soundManager:playSample(spec.samples.start)
		g_soundManager:playSample(spec.samples.work, 0, spec.samples.start)
	end
	self:setAnimationTime(spec.cutAnimation.name, 0, true)
	self:playAnimation(spec.cutAnimation.name, spec.cutAnimation.speedScale, self:getAnimationTime(spec.cutAnimation.name))
end
function Delimber:delimberReleaseGrabRotation(grabRotationReleased, noEventSend)
	local spec = self.spec_delimber
	if not spec.modInitialized or not spec.modAllowed then
		return
	end
	
	DelimberToggleGrabRotationEvent.sendEvent(self, grabRotationReleased, noEventSend)
	
	spec.grabRotationReleased = grabRotationReleased
end
function Delimber:getCanDelimb()
	local spec = self.spec_delimber
	if not spec.modInitialized or not spec.modAllowed then
		return
	end
	
	local canDelimb = true
	if spec.delimbClawsMovingTool ~= nil and spec.delimbClawsMovingTool ~= 0 then
		if self.spec_cylindered.movingTools[spec.delimbClawsMovingTool] ~= nil then
			if self.spec_cylindered.movingTools[spec.delimbClawsMovingTool].curRot[3] < self.spec_cylindered.movingTools[spec.delimbClawsMovingTool].rotMin + 0.2 then
				canDelimb = false
			end
		end
	end
	return canDelimb
end
function Delimber:actionCallback(actionName, keyStatus, arg4, arg5, arg6)
	local spec = self.spec_delimber
	if not spec.modInitialized or not spec.modAllowed then
		return
	end
	
	if self:getIsActive() then
		if keyStatus > 0 then
			if actionName == 'DELIMBER_CUT_TREE' then
				self:delimberCutTree(false)
			elseif actionName == 'DELIMBER_RELEASE_GRAB_ROTATION' then
				spec.grabRotationReleased = not spec.grabRotationReleased
				self:delimberReleaseGrabRotation(spec.grabRotationReleased, false)
			end
		end
	end
end
function Delimber:onDraw()
	local spec = self.spec_delimber
	if not spec.modInitialized or not spec.modAllowed then
		return
	end
	--renderText(0.69, 0.85, 0.013, spec.infoText)
end
function Delimber:onReadStream(streamId, connection)
	local spec = self.spec_delimber
	if not spec.modInitialized or not spec.modAllowed then
		return
	end
	spec.grabRotationReleased = streamReadBool(streamId)
	spec.delimbed = streamReadBool(streamId)
end
function Delimber:onWriteStream(streamId, connection)
	local spec = self.spec_delimber
	if not spec.modInitialized or not spec.modAllowed then
		return
	end
	streamWriteBool(streamId, spec.grabRotationReleased)
	streamWriteBool(streamId, spec.delimbed)
end

DelimberToggleGrabRotationEvent = {}
DelimberToggleGrabRotationEvent_mt = Class(DelimberToggleGrabRotationEvent, Event)

InitEventClass(DelimberToggleGrabRotationEvent, "DelimberToggleGrabRotationEvent")

function DelimberToggleGrabRotationEvent.emptyNew()
    local self = Event.new(DelimberToggleGrabRotationEvent_mt)
    self.className="DelimberToggleGrabRotationEvent"
    return self
end

function DelimberToggleGrabRotationEvent.new(object, grabRotationReleased)
	local self = DelimberToggleGrabRotationEvent.emptyNew()
	self.object = object
	self.grabRotationReleased = grabRotationReleased
	return self
end

function DelimberToggleGrabRotationEvent:readStream(streamId, connection)
	self.object = NetworkUtil.readNodeObject(streamId)
    self.grabRotationReleased = streamReadBool(streamId)
    self:run(connection)
end

function DelimberToggleGrabRotationEvent:writeStream(streamId, connection)
	NetworkUtil.writeNodeObject(streamId, self.object)
	streamWriteBool(streamId, self.grabRotationReleased)
end

function DelimberToggleGrabRotationEvent:run(connection)
	if self.object ~= nil then
		self.object:delimberReleaseGrabRotation(self.grabRotationReleased, true)
	end
	if not connection:getIsServer() then
		g_server:broadcastEvent(DelimberToggleGrabRotationEvent.new(self.object, self.grabRotationReleased), nil, connection, self.object)
	end
end

function DelimberToggleGrabRotationEvent.sendEvent(vehicle, grabRotationReleased, noEventSend)
	if noEventSend == nil or noEventSend == false then
		if g_server ~= nil then
			g_server:broadcastEvent(DelimberToggleGrabRotationEvent.new(vehicle, grabRotationReleased), nil, nil, vehicle)
		else
			g_client:getServerConnection():sendEvent(DelimberToggleGrabRotationEvent.new(vehicle, grabRotationReleased))
		end
	end
end

DelimberDelimbEvent = {}
DelimberDelimbEvent_mt = Class(DelimberDelimbEvent, Event)

InitEventClass(DelimberDelimbEvent, "DelimberDelimbEvent")

function DelimberDelimbEvent.emptyNew()
    local self = Event.new(DelimberDelimbEvent_mt)
    self.className="DelimberDelimbEvent"
    return self
end

function DelimberDelimbEvent.new(object, delimbed)
	local self = DelimberDelimbEvent.emptyNew()
	self.object = object
	self.delimbed = delimbed
	return self
end

function DelimberDelimbEvent:readStream(streamId, connection)
	self.object = NetworkUtil.readNodeObject(streamId)
    self.delimbed = streamReadBool(streamId)
    self:run(connection)
end

function DelimberDelimbEvent:writeStream(streamId, connection)
	NetworkUtil.writeNodeObject(streamId, self.object)
	streamWriteBool(streamId, self.delimbed)
end

function DelimberDelimbEvent:run(connection)
	if self.object ~= nil then
		self.object.spec_delimber.delimbed = true
	end
	if not connection:getIsServer() then
		g_server:broadcastEvent(DelimberDelimbEvent.new(self.object, self.delimbed), nil, connection, self.object)
	end
end

function DelimberDelimbEvent.sendEvent(vehicle, delimbed, noEventSend)
	if noEventSend == nil or noEventSend == false then
		if g_server ~= nil then
			g_server:broadcastEvent(DelimberDelimbEvent.new(vehicle, delimbed), nil, nil, vehicle)
		else
			g_client:getServerConnection():sendEvent(DelimberDelimbEvent.new(vehicle, delimbed))
		end
	end
end
