Merge pull request 'Check for duplicate Spawns and Scripts' (#20) from check-duplicates into master
All checks were successful
continuous-integration/drone/push Build is passing

Reviewed-on: #20
This commit is contained in:
itzaname 2024-05-01 01:30:28 +00:00
commit cb9300d1ef

View File

@ -200,26 +200,87 @@ async function validateMapAsset(assetId, game) {
} }
} }
const mapParts = root.FindDescendantsOfClass("BasePart", (part) => part.Name === "MapStart" || part.Name === "MapFinish"); const mapStarts = root.FindDescendantsOfClass("BasePart", (part) => part.Name === "MapStart");
if (mapParts.length !== 2 || mapParts[0].Name === mapParts[1].Name) { if (mapStarts.length !== 1) {
errors.push("Your map must have exactly one part named `MapStart` and one part named `MapFinish`."); errors.push("Your map must have exactly one part named `MapStart`.");
}
else if (mapParts[0].CanCollide || mapParts[1].CanCollide) {
errors.push("The `MapStart` and `MapFinish` parts in your map must have the `CanCollide` property disabled.");
} }
const spawnOnes = root.FindDescendantsOfClass("BasePart", (part) => part.Name === "Spawn1"); const mapFinishes = root.FindDescendantsOfClass("BasePart", (part) => part.Name === "MapFinish");
if (spawnOnes.length !== 1) { if (mapFinishes.length < 1) {
errors.push("Your map must have exactly one part named `Spawn1`."); errors.push("Your map must have at least one part named `MapFinish`.");
}
const mapParts = Array.from(mapStarts);
mapParts.push(...mapFinishes);
for (const part of mapParts) {
if (!part.CanCollide) {
errors.push("The `MapStart` and `MapFinish` parts in your map must have the `CanCollide` property disabled.");
break;
}
}
const allSpawns = root.FindDescendantsOfClass("BasePart", (part) => part.Name.startsWith("Spawn") && !isNaN(part.Name.slice(5)));
const spawnNameSet = new Set();
const duplicateSpawns = new Set();
for (const spawn of allSpawns) {
const name = spawn.Name;
if (spawnNameSet.has(name)) {
duplicateSpawns.add(name);
}
else {
spawnNameSet.add(name);
}
}
if (!spawnNameSet.has("Spawn1")) {
errors.push("Your map must have a part named `Spawn1`.");
}
const numDups = duplicateSpawns.size;
if (numDups > 0) {
const sortedSpawns = Array.from(duplicateSpawns);
sortedSpawns.sort();
const firstFive = sortedSpawns.slice(0, 5).map((name) => `\`${name}\``);
if (numDups > 1 && numDups <= 5) {
firstFive[firstFive.length - 1] = "and " + firstFive[firstFive.length - 1];
}
let msg = numDups === 1 ? "Your map has a duplicate `Spawn` part: " : "Your map has duplicate `Spawn` parts: ";
msg += firstFive.join(", ");
if (numDups > 5) {
msg += `, and ${numDups - 5} more`;
}
msg += ". There can only be one instance of each `Spawn` part.";
errors.push(msg);
} }
// Why does ModuleScript not inherit from Script, and/or why does BaseScript not have a Source property? // Why does ModuleScript not inherit from Script, and/or why does BaseScript not have a Source property?
const illegalScript = root.FindFirstDescendantOfClass("Script", (script) => sourceHasIllegalKeywords(script.Source)); const scripts = root.FindDescendantsOfClass("Script");
const illegalModuleScript = root.FindFirstDescendantOfClass("ModuleScript", (script) => sourceHasIllegalKeywords(script.Source)); scripts.push(...root.FindDescendantsOfClass("ModuleScript"));
if (illegalScript || illegalModuleScript) {
const sourceSet = new Set();
let numDuplicateScripts = 0;
let hasIllegalKeywords = false;
for (const script of scripts) {
const source = script.Source;
if (!hasIllegalKeywords && sourceHasIllegalKeywords(source)) {
hasIllegalKeywords = true;
}
if (sourceSet.has(source)) {
++numDuplicateScripts;
}
else {
sourceSet.add(source);
}
}
if (hasIllegalKeywords) {
errors.push("Your map has a `Script` that contains the keyword `getfenv` or `require`. You must remove these."); errors.push("Your map has a `Script` that contains the keyword `getfenv` or `require`. You must remove these.");
} }
if (numDuplicateScripts > 50) {
errors.push("Your map has over 50 duplicate `Script`s. You must consolidate your scripts to less than 50 duplicates.");
}
if (errors.length > 0) { if (errors.length > 0) {
return { return {
valid: false, valid: false,