AdditionalContractMapData = {};
AdditionalContractMapData.isLoaded = false;
AdditionalContractMapData.addConsoleCommand = true;
AdditionalContractMapData.CHANGE = 3;
AdditionalContractMapData.GROUND_ROAD = 1;
AdditionalContractMapData.GROUND_HARD_TERRAIN = 2;
AdditionalContractMapData.GROUND_SOFT_TERRAIN = 3;
AdditionalContractMapData.GROUND_FIELD = 4;
AdditionalContractMapData.GROUND_UNKNOWN = 5;
AdditionalContractMapData.STOREPLACE_TRIGGERS = {};
AdditionalContractMapData.LOAD_TRIGGERS = {WORKSHOPS=true, SELLINGSTATIONS=true, PRODUCTIONPOINTS=false};

local AdditionalContractMapData_mt = Class(AdditionalContractMapData);

function AdditionalContractMapData.new()	
	local self = {};
	setmetatable(self, AdditionalContractMapData_mt);	
	self.mapSplines = {splines={}, groundType={[1]={},[2]={},[3]={},[4]={},[5]={}}};	
	self.mapTriggers = {uniqueId={}, workshop={}, sellingStation={}, productionPoint={}};
	self.missionVehicles = {};
	self.hasMapTriggers = {unloadingStation=false,loadingStation=false};
	return self;
end;

function AdditionalContractMapData:loadMap(args)	
	
end;

function AdditionalContractMapData:onStartMap(args)	
	if not self:isDataLoaded() then --mp
		if g_server ~= nil then g_additionalContractMapData:loadSplines();end; --only on server
		g_additionalContractMapData:loadTriggers();
		g_additionalContractMapData:hasTriggers();
		g_additionalContractMapData:loadStoreSpawnPlace();
		AdditionalContractMapData.isLoaded = true;
	end;	
end;

function AdditionalContractMapData:isOnStartMap(args)
	
end;

function AdditionalContractMapData:isDataLoaded()
	return AdditionalContractMapData.isLoaded == true;
end;

function AdditionalContractMapData:loadStoreSpawnPlace()
	local storeSpawnPlaces = g_currentMission.storeSpawnPlaces;
	if storeSpawnPlaces ~= nil and #storeSpawnPlaces > 0 then
		for s=1, #storeSpawnPlaces do
			AdditionalContractMapData.STOREPLACE_TRIGGERS[s] = 
			{
				x=storeSpawnPlaces[s].startX; 
				y=storeSpawnPlaces[s].startY; 
				z=storeSpawnPlaces[s].startZ;
				rx=storeSpawnPlaces[s].rotX;
				ry=storeSpawnPlaces[s].rotY;
				rz=storeSpawnPlaces[s].rotZ;
				id=s;
				triggerTyp="storeSpawnPlace";
			};
		end;		
	end;
end;

function AdditionalContractMapData:loadSplines()
	local splines = g_currentMission.aiSystem.roadSplines;
	--print("+++load splines 1")
	if splines ~= nil and #splines > 0 then		
		local mapSize = Utils.getNoNil(g_currentMission.terrainSize, 2048) * 0.5
		for _, spline in pairs(splines) do
			if spline ~= nil then				
				local splineLength = getSplineLength(spline);
				local startX, startY, startZ = getSplinePosition(spline, 0);
				local endX, endY, endZ = getSplinePosition(spline, 1);				
				if startX ~= nil and endX ~= nil then
					if math.abs(startX) < mapSize and math.abs(startZ) < mapSize and math.abs(endX) < mapSize and math.abs(endZ) < mapSize then
						local splineName = getName(spline);						
						local rx, ry, rz = getSplineDirection(spline, 0);
						local rotY = MathUtil.getYRotationFromDirection(rx, rz);
						local rx1, ry1, rz1 = getSplineDirection(spline, 1);
						local rotY1 = MathUtil.getYRotationFromDirection(rx1, rz1);						
						local mapSpline = {length=splineLength, x=startX, y=startY, z=startZ, rx=rx, ry=ry, rz=rz, rotY=rotY, x1=endX, y1=endY, z1=endZ, rx1=rx1, ry1=ry1, rz1=rz1, rotY1=rotY1, name=splineName, groundType=AdditionalContractMapData.GROUND_UNKNOWN};
						
						table.insert(self.mapSplines.splines, mapSpline);						
						
						local _, _, _, groundDepth, _ = getTerrainAttributesAtWorldPos(g_terrainNode, startX, startY, startZ, true, true, true, true, false);						
						local groundTypeMapId, groundTypeFirstChannel, groundTypeNumChannels = g_currentMission.fieldGroundSystem:getDensityMapData(FieldDensityMap.GROUND_TYPE);
						local densityBits = getDensityAtWorldPos(groundTypeMapId, startX, startY, startZ);
						local densityHeightBits = bit32.rshift(densityBits, groundTypeFirstChannel);
						local numChannels = 2 ^ groundTypeNumChannels - 1;
						local heightType = bit32.band(densityHeightBits, numChannels);
						local densityType = FieldGroundType.getTypeByValue(heightType);						
						local groundType = self:getGroundType(densityType ~= FieldGroundType.NONE, false, groundDepth);
											
						if self.mapSplines.groundType[groundType] ~= nil then table.insert(self.mapSplines.groundType[groundType], mapSpline);else table.insert(self.mapSplines.groundType[AdditionalContractMapData.GROUND_UNKNOWN], mapSpline);end;
					end;
				end;
			end;
		end;
		--print("+++load splines length: ".. tostring(#self.mapSplines.splines))		
	end;	
end;

function AdditionalContractMapData:hasSplines(groundType)
	if groundType == nil then return #self.mapSplines.splines > 0, #self.mapSplines.splines;
	elseif self.mapSplines.groundType[groundType] ~= nil then return #self.mapSplines.groundType[groundType] > 0, #self.mapSplines.groundType[groundType];end;
	return false, 0;
end;

function AdditionalContractMapData:getRandomSpline(groundType)
	if groundType ~= nil then return self:getRandomSplineByGroundType(groundType);end;
	local randomSpline = math.random(1, #self.mapSplines.splines);	
	return self.mapSplines.splines[randomSpline];
end;

function AdditionalContractMapData:getRandomSplineByGroundType(groundType)
	if self.mapSplines.groundType[groundType] == nil or #self.mapSplines.groundType[groundType] <= 0 then return nil;end;
	return self.mapSplines.groundType[groundType][math.random(1, #self.mapSplines.groundType[groundType])];
end;

function AdditionalContractMapData:getRandomSplineByMinDistance(x, z, distance, groundType)
	local splines = self.mapSplines.splines;
	if groundType ~= nil then
		if self.mapSplines.groundType[groundType] == nil or #self.mapSplines.groundType[groundType] <= 0 then return nil;end;
		splines = self.mapSplines.groundType[groundType];
	end;
	local tempSplines = {};
	for _, spline in pairs(splines) do
		if g_additionalContractUtils:getObjectDistance( {x=x, z=z}, {x=spline.x, z=spline.z} ) >= distance then
			table.insert(tempSplines, spline);
		end;
	end;	
	return tempSplines[math.random(1, #tempSplines)];
end;

function AdditionalContractMapData:getRandomSplineByMaxDistance(x, z, distance, groundType)
	local splines = self.mapSplines.splines;
	if groundType ~= nil then
		if self.mapSplines.groundType[groundType] == nil or #self.mapSplines.groundType[groundType] <= 0 then return nil;end;
		splines = self.mapSplines.groundType[groundType];
	end;
	local tempSplines = {};
	for _, spline in pairs(splines) do
		if g_additionalContractUtils:getObjectDistance( {x=x, z=z}, {x=spline.x, z=spline.z} ) <= distance then
			table.insert(tempSplines, spline);
		end;
	end;	
	return tempSplines[math.random(1, #tempSplines)];
end;

function AdditionalContractMapData:getSpline(spline, groundType)	
	if groundType ~= nil and self.mapSplines.groundType[groundType] ~= nil and #self.mapSplines.groundType[groundType] > 0 then return self.mapSplines.groundType[groundType][spline];end;
	return self.mapSplines.splines[spline];
end;

function AdditionalContractMapData:getSplineByName(name)	
	for _, spline in pairs(self.mapSplines.splines) do
		if spline.name == name then
			return spline;
		end;
	end;
	return nil;	
end;

function AdditionalContractMapData:getSplineByPosition(x, z)	
	for _, spline in pairs(self.mapSplines.splines) do
		if spline.x == x and spline.z == z then
			return spline;
		end;
	end;
	return nil;	
end;

function AdditionalContractMapData:getSplineByIndex(index, groundType)	
	if groundType ~= nil then
		if self.mapSplines.groundType[groundType] ~= nil and #self.mapSplines.groundType[groundType] > 0 then 
			return self.mapSplines.groundType[groundType][spline];
		else
			return nil;
		end;	
	else
		return self.mapSplines.splines[spline];
	end;	
end;

function AdditionalContractMapData:loadTriggers()
	--print("+++load triggers 1")
	if g_currentMission.placeableSystem.placeables ~= nil then		
		function getUnloadTriggerData(unloadTrigger)
			local x, y, z, rx, ry, rz, triggerId, typ;
			if unloadTrigger.triggerNode ~= nil then 
				typ = "default";
				triggerId = unloadTrigger.triggerNode;
				x, y, z = getWorldTranslation(triggerId);
				rx, ry, rz = getWorldRotation(triggerId);
			elseif unloadTrigger.exactFillRootNode ~= nil then 
				typ = "exactFillRootNode";
				triggerId = unloadTrigger.exactFillRootNode;
				x, y, z = getWorldTranslation(triggerId);
				rx, ry, rz = getWorldRotation(triggerId);
			elseif unloadTrigger.baleTrigger ~= nil and unloadTrigger.baleTrigger.triggerNode ~= nil then 
				typ = "baleTrigger";
				triggerId = unloadTrigger.baleTrigger.triggerNode;
				x, y, z = getWorldTranslation(triggerId);
				rx, ry, rz = getWorldRotation(triggerId);
			elseif unloadTrigger.woodTrigger ~= nil and unloadTrigger.woodTrigger.triggerNode ~= nil then 
				typ = "woodTrigger";
				triggerId = unloadTrigger.woodTrigger.triggerNode
				x, y, z = getWorldTranslation(triggerId);
				rx, ry, rz = getWorldRotation(triggerId);
			end;
			return x, y, z, rx, ry, rz, triggerId, typ;
		end;
		for placeableUniqueId, placeable in pairs(g_currentMission.placeableSystem.placeables) do --placeables
			if placeable.spec_workshop and placeable.spec_workshop.sellingPoint and AdditionalContractMapData.LOAD_TRIGGERS.WORKSHOPS then                
				if placeable.spec_workshop.sellingPoint.sellTriggerNode and placeable.spec_workshop.sellingPoint.owningPlaceable ~= nil then
                    local x, y, z = getWorldTranslation(placeable.spec_workshop.sellingPoint.sellTriggerNode);
					local rx, ry, rz = getWorldRotation(placeable.spec_workshop.sellingPoint.sellTriggerNode);
					
					--local object = g_currentMission.nodeToObject[placeable.spec_workshop.sellingPoint.sellTriggerNode];
					--local name = object:getName();
					--local uniqueId = object:getUniqueId();
					
					local name = placeable:getName(); --placeable.spec_workshop.sellingPoint.owningPlaceable:getName();
					local uniqueId = placeable:getUniqueId(); --placeable.spec_workshop.sellingPoint.owningPlaceable:getUniqueId();
					
					local workshop = {uniqueId=uniqueId, triggerId=placeable.spec_workshop.sellingPoint.sellTriggerNode, farmId=placeable.ownerFarmId, triggerTyp="workshop", name=name, x=x, y=y, z=z, rx=rx, ry=ry, rz=rz};			
					table.insert(self.mapTriggers.workshop, workshop);					
					self.mapTriggers.uniqueId[uniqueId] = workshop;
					--local object = NetworkUtil.getObject(placeableUniqueId)
					--local objectUniqueId = object:getUniqueId();
					--local objectId = NetworkUtil.getObjectId(object)
					--print("1. workshop uniqueId: ".. tostring(uniqueId).. "/name: ".. tostring(name))
					--print("2. workshop objectId: ".. tostring(objectId).. "/objectUniqueId: ".. tostring(objectUniqueId))
					--print("3. workshop x: ".. tostring(x).. "/z: ".. tostring(z))
				end;
            elseif placeable.spec_sellingStation and placeable.spec_sellingStation.sellingStation and AdditionalContractMapData.LOAD_TRIGGERS.SELLINGSTATIONS then				
				if placeable.spec_sellingStation.sellingStation.unloadTriggers and placeable.spec_sellingStation.sellingStation.owningPlaceable ~= nil then
					local sellingStationNodeId = placeable.spec_sellingStation.sellingStation.rootNode or placeable.spec_sellingStation.sellingStation.nodeId;
					local isSellingPoint = placeable.spec_sellingStation.sellingStation.isSellingPoint;
					local name = placeable.spec_sellingStation.sellingStation.owningPlaceable:getName();
					local uniqueId = placeable.spec_sellingStation.sellingStation.owningPlaceable:getUniqueId();
					local xS, yS, zS = getWorldTranslation(sellingStationNodeId);
					local rxS, ryS, rzS = getWorldRotation(sellingStationNodeId);
					self.mapTriggers.uniqueId[uniqueId] = {uniqueId=uniqueId, x=xS, y=yS, z=zS, rx=rxS, ry=ryS, rz=rzS, isSellingPoint=isSellingPoint, farmId=placeable.ownerFarmId, triggerTyp="sellingStation", name=name, triggers={}};
					table.insert(self.mapTriggers.sellingStation, uniqueId);
					for _, unloadTrigger in pairs(placeable.spec_sellingStation.sellingStation.unloadTriggers) do
						local x, y, z, rx, ry, rz, triggerId, typ = getUnloadTriggerData(unloadTrigger);						
						if triggerId ~= nil and x ~= nil then							
							local trigger = {triggerId=triggerId, typ=typ, x=x, y=y, z=z, rx=rx, ry=ry, rz=rz};
							table.insert(self.mapTriggers.uniqueId[uniqueId].triggers, trigger);							
						end;
					end;					
				end;
			elseif placeable.spec_productionPoint and placeable.spec_productionPoint.productionPoint and placeable.spec_productionPoint.productionPoint.unloadingStation and AdditionalContractMapData.LOAD_TRIGGERS.PRODUCTIONPOINTS then
				if placeable.spec_productionPoint.productionPoint.unloadingStation.unloadTriggers and placeable.spec_productionPoint.productionPoint.owningPlaceable ~= nil then
					local productionPointNodeId = placeable.spec_productionPoint.productionPoint.node or placeable.spec_productionPoint.productionPoint.nodeId;					
					local name = placeable.spec_productionPoint.productionPoint.owningPlaceable:getName();
					local uniqueId = placeable.spec_productionPoint.productionPoint.owningPlaceable:getUniqueId();
					local xP, yP, zP = getWorldTranslation(productionPointNodeId);
					local rxP, ryP, rzP = getWorldRotation(productionPointNodeId);
					self.mapTriggers.uniqueId[uniqueId] = {uniqueId=uniqueId, x=xP, y=yP, z=zP, rx=rxP, ry=ryP, rz=rzP, farmId=placeable.ownerFarmId, triggerTyp="productionPoint", name=name, triggers={}};
					table.insert(self.mapTriggers.productionPoint, uniqueId);					
					for _, unloadTrigger in pairs(placeable.spec_productionPoint.productionPoint.unloadingStation.unloadTriggers) do
						local x, y, z, rx, ry, rz, triggerId, typ = getUnloadTriggerData(unloadTrigger);						
						if triggerId ~= nil and x ~= nil then							
							local trigger = {triggerId=triggerId, typ=typ, x=x, y=y, z=z, rx=rx, ry=ry, rz=rz};													
							table.insert(self.mapTriggers.uniqueId[uniqueId].triggers, trigger);
						end;
					end;
				end;
			end;			
		end;		
	end;
end;

function AdditionalContractMapData:hasMapTrigger(triggerTyp)
	if triggerTyp == nil or self.hasMapTriggers[triggerTyp] == nil then return false;end;
	return self.hasMapTriggers[triggerTyp];
end;

function AdditionalContractMapData:hasTrigger(triggerTyp)
	if triggerTyp == nil or self.mapTriggers[triggerTyp] == nil then return false,0;end;
	return #self.mapTriggers[triggerTyp] > 0, #self.mapTriggers[triggerTyp];
end;

function AdditionalContractMapData:getTrigger(triggerTyp, triggerPos)
	if triggerTyp == nil or self.mapTriggers[triggerTyp] == nil or #self.mapTriggers[triggerTyp] <= 0 then return nil;end;
	if triggerPos ~= nil then return self.mapTriggers[triggerTyp][triggerPos];end;
	return self:getRandomTrigger(triggerTyp);
end;

function AdditionalContractMapData:getTriggers(triggerTyp)
	if triggerTyp == nil or self.mapTriggers[triggerTyp] == nil or #self.mapTriggers[triggerTyp] <= 0 then return nil;end;
	return self.mapTriggers[triggerTyp];
end;

function AdditionalContractMapData:getRandomTrigger(triggerTyp)
	if self.mapTriggers[triggerTyp] == nil or #self.mapTriggers[triggerTyp] <= 0 then return nil;end;
	return self.mapTriggers[triggerTyp][math.random(1, #self.mapTriggers[triggerTyp])];
end;

function AdditionalContractMapData:getRandomTriggerEveryoneOrFarmId(triggerTyp, playerFarmId)
	if self.mapTriggers[triggerTyp] == nil or #self.mapTriggers[triggerTyp] <= 0 then return nil;end;
	local everyoneOrFarmIdTriggers = {};
	if playerFarmId == nil then 
		return self:getRandomTrigger(triggerTyp);
	else			
		for _, trigger in pairs(self.mapTriggers[triggerTyp]) do
			if trigger.farmId == AccessHandler.EVERYONE or trigger.farmId == playerFarmId then
				table.insert(everyoneOrFarmIdTriggers, trigger);
			end;
		end;
	end;
	if #everyoneOrFarmIdTriggers <= 0 then return nil;end;
	return everyoneOrFarmIdTriggers[math.random(1, #everyoneOrFarmIdTriggers)];
end;

function AdditionalContractMapData:getRandomTriggerNoFarmId(triggerTyp, playerFarmId)
	if self.mapTriggers[triggerTyp] == nil or #self.mapTriggers[triggerTyp] <= 0 then return nil;end;
	local noFarmIdTriggers = {};	
	for _, trigger in pairs(self.mapTriggers[triggerTyp]) do
		if trigger.farmId == AccessHandler.EVERYONE then --or not trigger.farmId == AccessHandler.NOBODY then
			table.insert(noFarmIdTriggers, trigger);
		end;
	end;
	if #noFarmIdTriggers <= 0 then return nil;end;
	return noFarmIdTriggers[math.random(1, #noFarmIdTriggers)];
end;

function AdditionalContractMapData:getTriggerByNetwork(pendingLoadingData)
	if pendingLoadingData.nodeObjectId ~= nil then
		local object = NetworkUtil.getObject(pendingLoadingData.nodeObjectId);
		if object ~= nil then return self:getTriggerByUniqueId(object:getUniqueId());end;	
	end;
	return nil;
end;

function AdditionalContractMapData:getTriggerByUniqueId(uniqueId)	
	return self.mapTriggers.uniqueId[uniqueId];	
end;

function AdditionalContractMapData:getTriggerByName(triggerTyp, triggerName)	
	for _, trigger in pairs(self.mapTriggers[triggerTyp]) do
		if trigger.name == triggerName then
			return trigger;
		end;
	end;
	return nil;	
end;

function AdditionalContractMapData:getTriggerByPosition(triggerTyp, x, z)	
	for _, trigger in pairs(self.mapTriggers[triggerTyp]) do
		if trigger.x == x and trigger.z == z then
			return trigger;
		end;
	end;
	return nil;	
end;

function AdditionalContractMapData:hasTriggerFlag(triggerNode, flag)
	return CollisionFlag.getHasMaskFlagSet(triggerNode, CollisionFlag[flag]);
end;

function AdditionalContractMapData:hasTriggers()
	for _, unloadingStation in pairs(g_currentMission.storageSystem:getUnloadingStations()) do
		if unloadingStation.owningPlaceable ~= nil and unloadingStation.isSellingPoint and unloadingStation.allowMissions then
			self.hasMapTriggers.unloadingStation = true;
			break;
		end;
	end;
	for _, loadingStation in pairs(g_currentMission.storageSystem:getLoadingStations()) do
		if loadingStation.owningPlaceable ~= nil and loadingStation.isSellingPoint and oadingStation.allowMissions then
			self.hasMapTriggers.loadingStation = true;
			break;
		end;
	end;
end;

function AdditionalContractMapData:hasMinFields(minFields)
	local fields = g_fieldManager:getFields();
	if fields ~= nil and #fields >= minFields then return true;end;
	return false;
end;

function AdditionalContractMapData:getRandomField(lastField, change)
	local fields = g_fieldManager:getFields();
	if fields ~= nil and #fields > 0 then 
		local change = change or 3;
		for i = math.random(1, #fields), #fields do
			if change <= 0 then break;end;
			local field = g_fieldManager.fields[i];
			if field ~= nil and field.getId ~= nil then
				local fieldId = field:getId();
				if fieldId ~= nil and fieldId ~= lastField then
					return self:getFieldById(fieldId);
				end;
			end;
			change = change - 1;
		end;
	end;
	return nil;
end;

function AdditionalContractMapData:getRandomFieldForMission(lastField, change)
	local field = g_fieldManager:getFieldForMission();
	if field ~= nil and field.getId ~= nil then 
		local fieldId = field:getId();
		if fieldId ~= nil and fieldId ~= lastField then			
			local x, z = field:getCenterOfFieldWorldPosition()
			local farmlandId = g_farmlandManager:getFarmlandIdAtWorldPosition(x, z);
			if farmlandId ~= nil and farmlandId > 0 then
				return {triggerId=fieldId, triggerTyp="field", farmlandId=farmlandId, x=x, y=0, z=z};
			end;			
		end;		
	end;
	if change ~= nil then return self:getRandomField(lastField, change);end;
	return nil;
end;

function AdditionalContractMapData:getFieldById(fieldId)
	local field = g_fieldManager:getFieldById(fieldId);
	if field ~= nil then				
		local x, z = field:getCenterOfFieldWorldPosition()
		local farmlandId = g_farmlandManager:getFarmlandIdAtWorldPosition(x, z);
		if farmlandId ~= nil and farmlandId > 0 then
			return {triggerId=fieldId, triggerTyp="field", farmlandId=farmlandId, x=x, y=0, z=z};
		end;			
	end;
	return nil;
end;

function AdditionalContractMapData:getStorePlaceTrigger(place, change)
	if AdditionalContractMapData.STOREPLACE_TRIGGERS ~= nil and #AdditionalContractMapData.STOREPLACE_TRIGGERS > 0 then
		if place ~= nil then
			if AdditionalContractMapData.STOREPLACE_TRIGGERS[place] ~= nil then
				return AdditionalContractMapData.STOREPLACE_TRIGGERS[place];			
			elseif change ~= nil and change then
				return self:getStorePlaceTrigger();
			end;
		else
			return AdditionalContractMapData.STOREPLACE_TRIGGERS[1]
		end;
	end;
	return nil;
end;

function AdditionalContractMapData:getStorePlaceTriggerByPosition(x, z)
	if AdditionalContractMapData.STOREPLACE_TRIGGERS ~= nil and #AdditionalContractMapData.STOREPLACE_TRIGGERS > 0 then
		for s=1, #AdditionalContractMapData.STOREPLACE_TRIGGERS do
			if AdditionalContractMapData.STOREPLACE_TRIGGERS[s].x == x and AdditionalContractMapData.STOREPLACE_TRIGGERS[s].z == z then
				return AdditionalContractMapData.STOREPLACE_TRIGGERS[s];			
			end;
		end;
	end;
	return nil;
end;

function AdditionalContractMapData:update(dt)
	
end;

function AdditionalContractMapData:getSellingStationWithHighestPrice(fillTypeIndex)
	local highestPrice = 0;
	local sellPoint = nil;
	for _, unloadingStation in pairs(g_currentMission.storageSystem:getUnloadingStations()) do
		if unloadingStation.owningPlaceable ~= nil and (unloadingStation.isSellingPoint and (unloadingStation.allowMissions and unloadingStation.acceptedFillTypes[fillTypeIndex])) then
			local price = unloadingStation:getEffectiveFillTypePrice(fillTypeIndex);
			if highestPrice < price then
				sellPoint = unloadingStation;
				highestPrice = price;
			end;
		end;
	end;	
	return sellPoint, highestPrice;
end;

function AdditionalContractMapData:isAvailableForSellingStation(sellingStation)
	return sellingStation ~= nil;
end;

function AdditionalContractMapData:getGroundType(isField, isRoad, groundDepth)
	if isField then
		return AdditionalContractMapData.GROUND_FIELD;
	elseif isRoad or groundDepth < 0.1 then
		return AdditionalContractMapData.GROUND_ROAD;
	elseif groundDepth > 0.8 then
		return AdditionalContractMapData.GROUND_SOFT_TERRAIN;
	else
		return AdditionalContractMapData.GROUND_HARD_TERRAIN;
	end;
end;
g_additionalContractMapData = AdditionalContractMapData.new();

function orgOnSavegameLoaded(self)	
	if g_server ~= nil then g_additionalContractMapData:loadSplines();end; --only on server
	g_additionalContractMapData:loadStoreSpawnPlace();
	g_additionalContractMapData:loadTriggers();
	g_additionalContractMapData:hasTriggers();
	AdditionalContractMapData.isLoaded = true;
end;
AutoSaveManager.onSavegameLoaded = Utils.appendedFunction(AutoSaveManager.onSavegameLoaded, orgOnSavegameLoaded);
--AutoSaveManager.onSavegameLoaded = Utils.prependedFunction(AutoSaveManager.onSavegameLoaded, orgOnSavegameLoaded);