How to redefine spawnpoints

So basically what we want to do in this tutorial is delete the old connections between capturepoint and spawnpoints and create them from scratch. We do that because then we can add as many spawnpoints as we like.
We will also change the position of the flagpole.

So in the beginning we define the capturepoint for which we would like to change the spawnpoints (which are AlternativeSpawnEntityData’s btw).

CPA = {
	GUID = Guid('5C3EEC89-4314-4714-8423-1D10A0270458'),
	POS = LinearTransform(
		Vec3(1, 0, 0), 
		Vec3(0, 1, 0), 
		Vec3(0, 0, 1), 
		Vec3(50.466816, 64.052544, 157.341797)),

	USSPAWNS = { LinearTransform(
					Vec3(-0.849120, 0.000000, -0.528200), 
					Vec3(0.0, 1.0, 0.0), 
					Vec3(0.528200, 0.000000, -0.849120), 
					Vec3(65.537018, 63.671684, 201.545914)),
				LinearTransform(
					Vec3(-0.810182, 0.000000, 0.586178), 
					Vec3(0.0, 1.0, 0.0), 
					Vec3(-0.586178, 0.000000, -0.810182), 
					Vec3(66.369141, 63.766407, 208.351563))
				},

	RUSPAWNS = { LinearTransform(
					Vec3(0.906630, 0.000000, -0.421926), 
					Vec3(0.0, 1.0, 0.0), 
					Vec3(0.421926, 0.000000, 0.906630), 
					Vec3(21.334951, 63.745972, 104.221687)),
				LinearTransform(
					Vec3(0.789017, 0.000000, -0.614371), 
					Vec3(0.0, 1.0, 0.0), 
					Vec3(0.614371, 0.000000, 0.789017), 
					Vec3(6.633789, 65.470505, 113.493164))
				 }
}

We have a Guid, a position, 2 US spawns and 2 RU spawns.

To define the SpawnPoints you should use the SpawnPointHelper by @Janssent. He has also contributed at the MP_Lake mod where I took most of this from.

Now we have set up the config. What is missing is the event and the deleting and adding part.
Let’s beginn with the event when we change all this stuff. For that we use the shared event Level:RegisterEntityResources.

Events:Subscribe('Level:RegisterEntityResources', function(levelData)
	-- change all stuff here
end)

About the guid: the guid is our capturepoint defined as a ReferenceObjectData.
For Métro Conquest Small it looks like this in webx:

You can also see that this is CapturePoint A if you look a bit closer:

I guess you know what to do, get all capturepoint guids you want to modify.
Then define additional to that the partitionGuid so we can load it:
local cqLogicPartitionGuid = Guid('F5DE48B8-29ED-4E73-B040-82637BE0E81C')

So your code should look like this:

CPA = {
     -- GUID, POS, USSPAWNS, RUSPAWNS
}

CPB = {
      -- GUID, POS, USSPAWNS, RUSPAWNS
}

-- etc.

local cqLogicPartitionGuid = Guid('F5DE48B8-29ED-4E73-B040-82637BE0E81C') -- your partition guid

Events:Subscribe('Level:RegisterEntityResources', function(levelData)
	-- change all stuff here
end)

At this point everything clear?

Fine, now we need the SubWorldData and then we can do the magic. The SubWorldData stores all connections. That’s why it is necessary for us.
Do this within the Level:RegisterEntityResources event:

	local subWorldData = ResourceManager:SearchForDataContainer("Levels/MP_Subway/Conquest_Small")
	if subWorldData ~= nil then
		subWorldData = SubWorldData(subWorldData)
		subWorldData:MakeWritable()
	end

BTW You can define the SpawnPoints now. If you use the SpawnPointHelper type something like this in console:

spawnpointhelper.load Levels/MP_Subway/Conquest_Small 5C3EEC89-4314-4714-8423-1D10A0270458 1

Of course with your level and your capturepoint Guid.

Like this:

And if you don’ t know how to use it just type spawnpointhelper.help into console.


Let’s go on with the mod. Now we are ready to delete all existing connections and add new ones.

	if subWorldData ~= nil then
		subWorldData = SubWorldData(subWorldData)
		subWorldData:MakeWritable()

		local cpAObjectData = ReferenceObjectData(ResourceManager:FindInstanceByGuid(cqLogicPartitionGuid, CPA.GUID))
		cpAObjectData:MakeWritable()
		cpAObjectData.blueprintTransform = CPA.POS
		ClearSpawnPoints(subWorldData, cpAObjectData)
		CreateSpawnPoints(subWorldData, cpAObjectData, CPA.USSPAWNS, "USCP")
		CreateSpawnPoints(subWorldData, cpAObjectData, CPA.RUSPAWNS, "RUCP")
	end

I guess this part needs deeper explanation.
Here we already changed the position of the capture point with: cpAObjectData.blueprintTransform = CPA.POS
I already added ClearSpawnPoints and CreateSpawnPoints but we didn’t define these functions yet.
But this is what we will do now.

As I said before the SubWorldData stores all connections so now we loop through the linkConnections and erase everything that links from our capturepoint to a spawnpoint.

function ClearSpawnPoints(subWorldData, cpObjectData)
	-- Since we are removing stuff, iterate through the connections in reverse order.
	for i = #subWorldData.linkConnections, 1, -1 do

		local connection = subWorldData.linkConnections[i]

		if connection.target:Is("AlternateSpawnEntityData") then

			if connection.source == cpObjectData then

				subWorldData.linkConnections:erase(i)
			end
		end
	end
end

This clears all spawn points of that capture point.
We check if the target is a spawnpoint (AlternateSpawnEntityData) and if the source is our capturepoint (cpObjectData ). If so, then we erase it.
Now we only need to add the new ones and we are done. For that we need some eventHashes:

local teamAndHash = {
	["USCP"] = { 0, 1751730141 }, --TeamID, eventID/eventHash
	["RUCP"] = { 0, 1879290430 },
	["USHQ"] = { 1, -2001390482 },
	["RUHQ"] = { 2, -2001390482 },
	-- TDM/ SQDM/ Gunmaster
	["DM1"] = {0, -1404628591},
	["DM2"] = {0, -890967278},
	-- SQDM
	["DM3"] = {0, 465180179},
	["DM4"] = {0, 1475647380}
}

We will only use USCP and RUCP but if you want to edit the base spawns too you will need USHQ and RUHQ.

Now we do the last part to add the connections:

function CreateSpawnPoints(subWorldData, cpObjectData, spawns, type)
	
	for _, spawnTransform in pairs(spawns) do

		local alternateSpawn = AlternateSpawnEntityData()
		alternateSpawn.team = teamAndHash[type][1]
		alternateSpawn.transform = spawnTransform
		
		-- The sourceFieldId depends on what team the spawn belongs to. Base spawns have a different one as well.
		local connection = LinkConnection()
		connection.target = alternateSpawn
		connection.source = cpObjectData
		connection.sourceFieldId = teamAndHash[type][2]
		subWorldData.linkConnections:add(connection)
	end

end

You see we loop through the spawns and create an AlternateSpawnEntityData() and a LinkConnection() for all of them.

Remember we do:

CreateSpawnPoints(subWorldData, cpAObjectData, CPA.USSPAWNS, "USCP")
CreateSpawnPoints(subWorldData, cpAObjectData, CPA.RUSPAWNS, "RUCP")

So spawns is a table with all our stored spawns as LinearTransforms and type is either "USCP" or "RUCP".
Both of them will define alternateSpawn.team = 0 but the connection.sourceFieldId will be different.

Well and that’s it. I hope you could follow this. If you want you can also take a look at the MP_Lake mod for reference.

Note that we didnt change the capturepoint zone as we discussed that already in the How to adjust the redzones and capturepoint areas tutorial.

11 Likes

So I keep seeing this GUID s everywhere … what are those ? Why are they important ?

1 Like
2 Likes

Thanks ! I already took a look through the guides but couldn’t find anything related to the GUIDs specifically - Do you have a direct link to the part where it is explained maybe ?

Update
Ah - Found it : https://docs.veniceunleashed.net/vext/guides/data/ :slight_smile: thanks

1 Like

Hi! Can you tell me please how i can add new vehicle spawn point? For example: i want to add new vehicle lav25 on map operation faerstorm