forked from 0ad/0ad
Add mod selection mod.
Includes some contributions by rada and sanderd17. This was SVN commit r15677.
This commit is contained in:
parent
523d220ac5
commit
64bfa089af
@ -374,3 +374,6 @@ lobby.history = 0 ; Number of past messages to display o
|
||||
; Overlay Preferences
|
||||
overlay.fps = "false" ; Show frames per second in top right corner
|
||||
overlay.realtime = "false" ; Show current system time in top right corner
|
||||
|
||||
; MOD SETTINGS
|
||||
;mod.enabledmods = "mod public"
|
||||
|
494
binaries/data/mods/mod/gui/modmod/modmod.js
Normal file
494
binaries/data/mods/mod/gui/modmod/modmod.js
Normal file
@ -0,0 +1,494 @@
|
||||
/*
|
||||
Example contents of g_mods:
|
||||
{
|
||||
"foldername1": { // this is the content of the json file in a specific mod
|
||||
name: "unique_shortname", // eg "0ad", "rote"
|
||||
version: "0.0.16",
|
||||
label: "Nice Mod Name", // eg "0 A.D. - Empires Ascendant"
|
||||
type: "content|functionality|mixed/mod-pack",
|
||||
url: "http://wildfregames.com/",
|
||||
description: "",
|
||||
dependencies: [] // (name({<,<=,==,>=,>}version)?)+
|
||||
},
|
||||
"foldername2": {
|
||||
name: "mod2",
|
||||
label: "Mod 2",
|
||||
version: "1.1",
|
||||
type: "content|functionality|mixed/mod-pack",
|
||||
url: "http://play0ad.wfg.com/",
|
||||
description: "",
|
||||
dependencies: []
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
var g_mods = {}; // Contains all JSONs as explained in the structure above
|
||||
var g_modsEnabled = []; // folder names
|
||||
var g_modsAvailable = []; // folder names
|
||||
|
||||
const g_sortByOptions = [translate("Name"), translate("Label"), translate("Folder"), translate("Version")];
|
||||
const SORT_BY_NAME = 0;
|
||||
const SORT_BY_FOLDER = 1;
|
||||
const SORT_BY_LABEL = 2;
|
||||
const SORT_BY_VERSION = 3;
|
||||
|
||||
var g_modTypes = [translate("Type: Any")];
|
||||
|
||||
/**
|
||||
* Fetches the mod lists in JSON from the Engine.
|
||||
* Initiates a first creation of the GUI lists.
|
||||
* Enabled mods are read from the Configuration and checked if still available.
|
||||
*/
|
||||
function init()
|
||||
{
|
||||
g_mods = Engine.GetAvailableMods();
|
||||
|
||||
g_modsEnabled = getExistingModsFromConfig();
|
||||
g_modsAvailable = Object.keys(g_mods).filter(function(i) { return g_modsEnabled.indexOf(i) === -1; });
|
||||
|
||||
Engine.GetGUIObjectByName("negateFilter").checked = false;
|
||||
Engine.GetGUIObjectByName("modGenericFilter").caption = translate("Filter");
|
||||
Engine.GetGUIObjectByName("modTypeFilter").selected = 0;
|
||||
|
||||
var sortBy = Engine.GetGUIObjectByName("sortBy");
|
||||
sortBy.list = g_sortByOptions;
|
||||
sortBy.selected = SORT_BY_NAME;
|
||||
|
||||
// sort ascending by default
|
||||
Engine.GetGUIObjectByName("isOrderDescending").checked = false;
|
||||
|
||||
generateModsLists();
|
||||
|
||||
Engine.GetGUIObjectByName("message").caption = translate("Message: Mods Loaded.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Recreating both the available and enabled mods lists.
|
||||
*/
|
||||
function generateModsLists()
|
||||
{
|
||||
generateModsList('modsAvailableList', g_modsAvailable);
|
||||
generateModsList('modsEnabledList', g_modsEnabled);
|
||||
}
|
||||
|
||||
function saveMods()
|
||||
{
|
||||
// always sort mods before saving
|
||||
sortMods();
|
||||
Engine.ConfigDB_CreateValue("user", "mod.enabledmods", ["mod"].concat(g_modsEnabled).join(" "));
|
||||
Engine.ConfigDB_WriteFile("user", "config/user.cfg");
|
||||
}
|
||||
|
||||
function startMods()
|
||||
{
|
||||
// always sort mods before starting
|
||||
sortMods();
|
||||
Engine.SetMods(["mod"].concat(g_modsEnabled));
|
||||
Engine.RestartEngine();
|
||||
}
|
||||
|
||||
function getExistingModsFromConfig()
|
||||
{
|
||||
var existingMods = [];
|
||||
|
||||
var mods = [];
|
||||
var cfgMods = Engine.ConfigDB_GetValue("user", "mod.enabledmods");
|
||||
if (cfgMods.length > 0)
|
||||
mods = cfgMods.split(/\s+/);
|
||||
|
||||
mods.forEach(function(mod) {
|
||||
if (mod in g_mods)
|
||||
existingMods.push(mod);
|
||||
});
|
||||
|
||||
return existingMods;
|
||||
}
|
||||
|
||||
/**
|
||||
* (Re-)Generate List of all mods.
|
||||
* @param listObjectName The GUI object's name (e.g. "modsEnabledList", "modsAvailableList")
|
||||
*/
|
||||
function generateModsList(listObjectName, mods)
|
||||
{
|
||||
var sortBy = Engine.GetGUIObjectByName("sortBy");
|
||||
var orderDescending = Engine.GetGUIObjectByName("isOrderDescending");
|
||||
var isDescending = orderDescending && orderDescending.checked;
|
||||
|
||||
// TODO: Sorting mods by dependencies would be nice
|
||||
if (listObjectName != "modsEnabledList")
|
||||
{
|
||||
var idx = -1;
|
||||
if (sortBy)
|
||||
idx = sortBy.selected;
|
||||
|
||||
switch (idx)
|
||||
{
|
||||
default:
|
||||
warn("generateModsList: invalid index '"+idx+"'"); // fall through
|
||||
// sort by unique name alphanumerically by default:
|
||||
case -1:
|
||||
case SORT_BY_NAME:
|
||||
mods.sort(function(a, b)
|
||||
{
|
||||
var ret = compare(g_mods[a].name.toLowerCase(), g_mods[b].name.toLowerCase());
|
||||
return ret * (isDescending ? -1 : 1);
|
||||
});
|
||||
break;
|
||||
case SORT_BY_FOLDER:
|
||||
mods.sort(function(a, b)
|
||||
{
|
||||
return compare(a.toLowerCase(), b.toLowerCase()) * (isDescending ? -1 : 1);
|
||||
});
|
||||
break;
|
||||
case SORT_BY_LABEL:
|
||||
mods.sort(function(a, b)
|
||||
{
|
||||
var ret = compare(g_mods[a].label.toLowerCase(), g_mods[b].label.toLowerCase());
|
||||
return ret * (isDescending ? -1 : 1);
|
||||
});
|
||||
break;
|
||||
case SORT_BY_VERSION:
|
||||
mods.sort(function(a, b)
|
||||
{
|
||||
// TODO reuse actual logic
|
||||
var ret = compare(g_mods[a].version, g_mods[b].version);
|
||||
return ret * (isDescending ? -1 : 1);
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var [names, folders, labels, types, urls, versions, dependencies] = [[],[],[],[],[],[],[]];
|
||||
mods.forEach(function(foldername)
|
||||
{
|
||||
var mod = g_mods[foldername];
|
||||
if (mod.type && g_modTypes.indexOf(mod.type) == -1)
|
||||
g_modTypes.push(mod.type);
|
||||
|
||||
if (filterMod(foldername))
|
||||
return;
|
||||
|
||||
names.push(mod.name);
|
||||
folders.push('[color="45 45 45"](' + foldername + ')[/color]');
|
||||
|
||||
labels.push(mod.label || "");
|
||||
types.push(mod.type || "");
|
||||
urls.push(mod.url || "");
|
||||
versions.push(mod.version || "");
|
||||
dependencies.push((mod.dependencies || []).join(" "));
|
||||
});
|
||||
|
||||
// Update the list
|
||||
var obj = Engine.GetGUIObjectByName(listObjectName);
|
||||
obj.list_name = names;
|
||||
obj.list_modFolderName = folders;
|
||||
obj.list_modLabel = labels;
|
||||
obj.list_modType = types;
|
||||
obj.list_modURL = urls;
|
||||
obj.list_modVersion = versions;
|
||||
obj.list_modDependencies = dependencies;
|
||||
|
||||
obj.list = names;
|
||||
|
||||
var modTypeFilter = Engine.GetGUIObjectByName("modTypeFilter");
|
||||
modTypeFilter.list = g_modTypes;
|
||||
}
|
||||
|
||||
function compare(a, b)
|
||||
{
|
||||
return ( (a > b) ? 1 : (b > a) ? -1 : 0 );
|
||||
}
|
||||
|
||||
function enableMod()
|
||||
{
|
||||
var obj = Engine.GetGUIObjectByName("modsAvailableList");
|
||||
var pos = obj.selected;
|
||||
if (pos === -1)
|
||||
return;
|
||||
|
||||
var mod = g_modsAvailable[pos];
|
||||
|
||||
// Move it to the other table
|
||||
// check dependencies, warn about not satisfied dependencies and abort if so:
|
||||
if (!areDependenciesMet(mod))
|
||||
return;
|
||||
|
||||
g_modsEnabled.push(g_modsAvailable.splice(pos, 1)[0]);
|
||||
|
||||
if (pos >= g_modsAvailable.length)
|
||||
pos--;
|
||||
obj.selected = pos;
|
||||
|
||||
generateModsLists();
|
||||
}
|
||||
|
||||
function disableMod()
|
||||
{
|
||||
var obj = Engine.GetGUIObjectByName("modsEnabledList");
|
||||
var pos = obj.selected;
|
||||
if (pos === -1)
|
||||
return;
|
||||
|
||||
var mod = g_modsEnabled[pos];
|
||||
|
||||
g_modsAvailable.push(g_modsEnabled.splice(pos, 1)[0]);
|
||||
|
||||
// Remove mods that required the removed mod and cascade
|
||||
// Sort them, so we know which ones can depend on the removed mod
|
||||
// TODO: Find position where the removed mod would have fit (for now assume idx 0)
|
||||
sortMods();
|
||||
for (var i = 0; i < g_modsEnabled.length; ++i)
|
||||
{
|
||||
if (!areDependenciesMet(g_modsEnabled[i]))
|
||||
{
|
||||
g_modsAvailable.push(g_modsEnabled.splice(i, 1)[0]);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
|
||||
// select the last element even if more than 1 mod has been removed:
|
||||
if (pos > g_modsEnabled.length - 1)
|
||||
pos = g_modsEnabled.length - 1;
|
||||
obj.selected = pos;
|
||||
|
||||
generateModsLists();
|
||||
}
|
||||
|
||||
function resetFilters()
|
||||
{
|
||||
// Reset states of gui objects.
|
||||
Engine.GetGUIObjectByName("modTypeFilter").selected = 0;
|
||||
Engine.GetGUIObjectByName("negateFilter").checked = false;
|
||||
Engine.GetGUIObjectByName("modGenericFilter").caption = "";
|
||||
|
||||
// NOTE: Calling generateModsLists() is not needed as the selection changes and that calls applyFilters()
|
||||
}
|
||||
|
||||
function applyFilters()
|
||||
{
|
||||
Engine.GetGUIObjectByName("modsAvailableList").selected = -1;
|
||||
Engine.GetGUIObjectByName("modsEnabledList").selected = -1;
|
||||
generateModsLists();
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter a mod based on the status of the filters.
|
||||
*
|
||||
* @param modFolder Mod to be tested.
|
||||
* @return True if mod should not be displayed.
|
||||
*/
|
||||
function filterMod(modFolder)
|
||||
{
|
||||
var mod = g_mods[modFolder];
|
||||
|
||||
var modTypeFilter = Engine.GetGUIObjectByName("modTypeFilter");
|
||||
var genericFilter = Engine.GetGUIObjectByName("modGenericFilter");
|
||||
var negateFilter = Engine.GetGUIObjectByName("negateFilter");
|
||||
|
||||
// TODO: and result of filters together (type && generic)
|
||||
|
||||
// We assume index 0 means display all for any given filter.
|
||||
if (modTypeFilter.selected > 0
|
||||
&& (mod.type || "") != modTypeFilter.list[modTypeFilter.selected])
|
||||
return !negateFilter.checked;
|
||||
|
||||
if (genericFilter && genericFilter.caption && genericFilter.caption != "" && genericFilter.caption != "Filter")
|
||||
{
|
||||
var t = genericFilter.caption;
|
||||
if (modFolder.indexOf(t) === -1
|
||||
&& mod.name.indexOf(t) === -1
|
||||
&& mod.label.indexOf(t) === -1
|
||||
&& (mod.type || "").indexOf(t) === -1
|
||||
&& mod.url.indexOf(t) === -1
|
||||
&& mod.version.indexOf(t) === -1
|
||||
&& mod.description.indexOf(t) === -1
|
||||
&& mod.dependencies.indexOf(t) === -1)
|
||||
{
|
||||
return !negateFilter.checked;
|
||||
}
|
||||
}
|
||||
|
||||
return negateFilter.checked;
|
||||
}
|
||||
|
||||
function closePage()
|
||||
{
|
||||
Engine.SwitchGuiPage("page_pregame.xml", {});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Moves an item in the list @p objectName up or down depending on the value of @p up.
|
||||
*/
|
||||
function moveCurrItem(objectName, up)
|
||||
{
|
||||
// reuse the check for null and if something is selected.
|
||||
if (getCurrItemValue(objectName) == "")
|
||||
return;
|
||||
|
||||
var idx = Engine.GetGUIObjectByName(objectName).selected;
|
||||
if (idx === -1)
|
||||
return;
|
||||
|
||||
var num = getNumItems(objectName);
|
||||
var idx2 = idx + (up ? -1 : 1);
|
||||
if (idx2 < 0 || idx2 >= num)
|
||||
return;
|
||||
|
||||
var tmp = g_modsEnabled[idx];
|
||||
g_modsEnabled[idx] = g_modsEnabled[idx2];
|
||||
g_modsEnabled[idx2] = tmp;
|
||||
|
||||
// Selected object reached the new position.
|
||||
Engine.GetGUIObjectByName(objectName).list = g_modsEnabled;
|
||||
Engine.GetGUIObjectByName(objectName).selected = idx2;
|
||||
generateModsList('modsEnabledList', g_modsEnabled);
|
||||
}
|
||||
|
||||
function areDependenciesMet(mod)
|
||||
{
|
||||
var guiObject = Engine.GetGUIObjectByName("message");
|
||||
for each (var dependency in g_mods[mod].dependencies)
|
||||
{
|
||||
if (isDependencyMet(dependency))
|
||||
continue;
|
||||
guiObject.caption = '[color="250 100 100"]' + translate(sprintf('Dependency not met: %(dep)s', { "dep": dependency })) +'[/color]';
|
||||
return false;
|
||||
}
|
||||
|
||||
guiObject.caption = '[color="100 250 100"]' + translate('All dependencies met') + '[/color]';
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param dependency: Either id (unique modJson.name) and version or only the unique mod name.
|
||||
* Concatenated by either "=", ">", "<", ">=", "<=".
|
||||
*/
|
||||
function isDependencyMet(dependency_idAndVersion, modsEnabled = null)
|
||||
{
|
||||
if (!modsEnabled)
|
||||
modsEnabled = g_modsEnabled;
|
||||
|
||||
// Split on {=,<,<=,>,>=} and use the second part as the version number
|
||||
// and whatever we split on as a way to handle that version.
|
||||
var op = dependency_idAndVersion.match(/(<=|>=|<|>|=)/);
|
||||
// Did the dependency contain a version number?
|
||||
if (op)
|
||||
{
|
||||
op = op[0];
|
||||
var dependency_parts = dependency_idAndVersion.split(op);
|
||||
var dependency_version = dependency_parts[1];
|
||||
var dependency_id = dependency_parts[0];
|
||||
}
|
||||
else
|
||||
var dependency_id = dependency_idAndVersion;
|
||||
|
||||
// modsEnabled_key currently is the mod folder name.
|
||||
for each (var modsEnabled_key in modsEnabled)
|
||||
{
|
||||
var modJson = g_mods[modsEnabled_key];
|
||||
if (modJson.name != dependency_id)
|
||||
continue;
|
||||
|
||||
// There could be another mod with a satisfying version
|
||||
if (!op || versionSatisfied(modJson.version, op, dependency_version))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if @p version satisfies @p op (<,<=,=,>=,>) @p requirement.
|
||||
* @note @p version and @p requirement are split on '.' and everything after
|
||||
* '-' or '_' is ignored. Only numbers are supported.
|
||||
* @note "5.3" < "5.3.0"
|
||||
*/
|
||||
function versionSatisfied(version, op, requirement)
|
||||
{
|
||||
var reqList = requirement.split(/[-_]/)[0].split(/\./g);
|
||||
var avList = version.split(/[-_]/)[0].split(/\./g);
|
||||
|
||||
var eq = op.indexOf("=") !== -1;
|
||||
var lt = op.indexOf("<") !== -1;
|
||||
var gt = op.indexOf(">") !== -1;
|
||||
if (!(eq || lt || gt))
|
||||
{
|
||||
warn("No valid compare op");
|
||||
return false;
|
||||
}
|
||||
|
||||
var l = Math.min(reqList.length, avList.length);
|
||||
for (var i = 0; i < l; ++i)
|
||||
{
|
||||
// TODO: Handle NaN
|
||||
var diff = +avList[i] - +reqList[i];
|
||||
|
||||
// Early success
|
||||
if (gt && diff > 0)
|
||||
return true;
|
||||
if (lt && diff < 0)
|
||||
return true;
|
||||
|
||||
// Early failure
|
||||
if (gt && diff < 0)
|
||||
return false;
|
||||
if (lt && diff > 0)
|
||||
return false;
|
||||
if (eq && diff !== 0)
|
||||
return false;
|
||||
}
|
||||
// common prefix matches
|
||||
var ldiff = avList.length - reqList.length;
|
||||
if (ldiff === 0)
|
||||
return eq;
|
||||
// NB: 2.3 != 2.3.0
|
||||
if (ldiff < 0)
|
||||
return lt;
|
||||
if (ldiff > 0)
|
||||
return gt;
|
||||
|
||||
// Can't be reached
|
||||
error("version checking code broken");
|
||||
return false;
|
||||
}
|
||||
|
||||
function sortMods()
|
||||
{
|
||||
// store the list of dependencies per mod, but strip the version numbers
|
||||
var deps = {};
|
||||
for (var mod of g_modsEnabled)
|
||||
{
|
||||
deps[mod] = [];
|
||||
if (!g_mods[mod].dependencies)
|
||||
continue;
|
||||
deps[mod] = g_mods[mod].dependencies.map(function(d) { return d.split(/(<=|>=|<|>|=)/)[0]; });
|
||||
}
|
||||
var sortFunction = function(mod1, mod2)
|
||||
{
|
||||
var name1 = g_mods[mod1].name;
|
||||
var name2 = g_mods[mod2].name;
|
||||
if (deps[mod1].indexOf(name2) != -1)
|
||||
return 1;
|
||||
if (deps[mod2].indexOf(name1) != -1)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
g_modsEnabled.sort(sortFunction);
|
||||
generateModsList("modsEnabledList", g_modsEnabled);
|
||||
}
|
||||
|
||||
function showModDescription(listObjectName, mod_keys)
|
||||
{
|
||||
var listObject = Engine.GetGUIObjectByName(listObjectName);
|
||||
if (listObject.selected == -1)
|
||||
var desc = '[color="255 100 100"]' + translate("No mod has been selected.") + '[/color]';
|
||||
else
|
||||
{
|
||||
var mod_key = mod_keys[listObject.selected];
|
||||
var desc = g_mods[mod_key].description;
|
||||
}
|
||||
|
||||
Engine.GetGUIObjectByName("globalModDescription").caption = desc;
|
||||
}
|
192
binaries/data/mods/mod/gui/modmod/modmod.xml
Normal file
192
binaries/data/mods/mod/gui/modmod/modmod.xml
Normal file
@ -0,0 +1,192 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<objects>
|
||||
<script file="gui/modmod/modmod.js"/>
|
||||
|
||||
<object name="modmod" type="image" style="ModernWindow" size="0 0 100% 100%">
|
||||
<!-- Page Title -->
|
||||
<object style="ModernLabelText" type="text" size="50%-128 4 50%+128 36">
|
||||
<translatableAttribute id="caption">Modifications</translatableAttribute>
|
||||
</object>
|
||||
|
||||
<!-- Message -->
|
||||
<object name="message" type="text" size="15 40 100%-15 88" text_align="left" textcolor="white"/>
|
||||
|
||||
<!-- reset filters -->
|
||||
<object name="resetFilters" size="15 72 184 100" type="button" style="ModernButtonRed">
|
||||
<translatableAttribute id="caption">Reset Filters</translatableAttribute>
|
||||
<action on="Press">resetFilters();</action>
|
||||
</object>
|
||||
|
||||
<!-- Filter Panel -->
|
||||
<object name="filterPanel" size="184 64 50% 98">
|
||||
<object name="modGenericFilter"
|
||||
type="input"
|
||||
style="ModernInput"
|
||||
size="10 100%-24 170 100%"
|
||||
>
|
||||
<action on="Press">applyFilters();</action>
|
||||
</object>
|
||||
|
||||
<object name="modTypeFilter"
|
||||
type="dropdown"
|
||||
style="ModernDropDown"
|
||||
size="180 100%-24 350 100%"
|
||||
font="sans-bold-13"
|
||||
>
|
||||
<action on="SelectionChange">applyFilters();</action>
|
||||
</object>
|
||||
|
||||
<!-- Checkboxes -->
|
||||
<object name="negateFilter"
|
||||
type="checkbox"
|
||||
checked="false"
|
||||
style="ModernTickBox"
|
||||
size="355 100%-24 375 100%"
|
||||
font="serif-bold-13"
|
||||
>
|
||||
<action on="Press">applyFilters();</action>
|
||||
</object>
|
||||
<object type="text" size="377 100%-24 460 100%" text_align="left" textcolor="white">
|
||||
<translatableAttribute id="caption">Negate</translatableAttribute>
|
||||
</object>
|
||||
</object>
|
||||
|
||||
<!-- Sort by -->
|
||||
<object name="sortingWrapper" size="100%-400 74 100% 98">
|
||||
<object type="text" size="0 0 75 100%" text_align="left" textcolor="white">
|
||||
Sorting:
|
||||
</object>
|
||||
<object name="sortBy"
|
||||
type="dropdown"
|
||||
style="ModernDropDown"
|
||||
size="75 100%-24 75%-25 100%"
|
||||
font="sans-bold-13"
|
||||
>
|
||||
<action on="SelectionChange">applyFilters();</action>
|
||||
</object>
|
||||
<!-- Checkboxes -->
|
||||
<object type="text" size="75% 100%-24 100% 100%" text_align="left" textcolor="white">
|
||||
Descending.
|
||||
</object>
|
||||
<object name="isOrderDescending"
|
||||
type="checkbox"
|
||||
checked="false"
|
||||
style="ModernTickBox"
|
||||
size="75%-20 100%-24 75% 100%"
|
||||
font="serif-bold-13"
|
||||
>
|
||||
<action on="Press">applyFilters();</action>
|
||||
</object>
|
||||
</object>
|
||||
|
||||
<!-- Available Mods Wrapper -->
|
||||
<object name="modsAvailable" size="16 100 100%-15 75%-4" style="ModmodScrollbar">
|
||||
<object style="ModernLabelText" type="text" size="0 5 100% 25">
|
||||
<translatableAttribute id="caption">Available Mods</translatableAttribute>
|
||||
</object>
|
||||
|
||||
<object name="modsAvailableList" style="ModernList" type="olist" size="0 25 100%-2 100%" font="sans-stroke-13">
|
||||
<action on="SelectionChange">showModDescription(this.name, g_modsAvailable);</action>
|
||||
<!-- List headers -->
|
||||
<def id="name" color="100 100 200" width="10%">
|
||||
<translatableAttribute id="heading">Name</translatableAttribute>
|
||||
</def>
|
||||
<def id="modVersion" color="128 128 128" width="5%">
|
||||
<translatableAttribute id="heading">Version</translatableAttribute>
|
||||
</def>
|
||||
<def id="modFolderName" color="100 100 200" width="15%">
|
||||
<translatableAttribute id="heading">(Folder)</translatableAttribute>
|
||||
</def>
|
||||
<def id="modLabel" color="0 60 0" width="18%">
|
||||
<translatableAttribute id="heading">Mod Label</translatableAttribute>
|
||||
</def>
|
||||
<def id="modType" color="0 128 128" width="12%">
|
||||
<translatableAttribute id="heading">Mod Type</translatableAttribute>
|
||||
</def>
|
||||
<def id="modDependencies" color="128 128 128" width="20%">
|
||||
<translatableAttribute id="heading">Dependencies</translatableAttribute>
|
||||
</def>
|
||||
<def id="modURL" color="128 128 128" width="24%">
|
||||
<translatableAttribute id="heading">Website</translatableAttribute>
|
||||
</def>
|
||||
</object>
|
||||
<object name="globalModDescription" type="text" style="ModmodScrollbar" size="0 100%-28 100%-16 100%">
|
||||
<attribute id="caption"><keep>[color="100 100 100"]</keep><translate>Description</translate><keep>[/color]</keep></attribute>
|
||||
</object>
|
||||
<object type="button" style="ModernButtonRed" size="100%-184 100%-28 100% 100%">
|
||||
<translatableAttribute id="caption">Enable</translatableAttribute>
|
||||
<action on="Press">enableMod();</action>
|
||||
</object>
|
||||
</object>
|
||||
|
||||
|
||||
<!-- Enabled Mods Wrapper -->
|
||||
<object name="modsEnabled" size="16 75% 100%-15 100%-50">
|
||||
<object style="ModernLabelText" type="text" size="0 5 100% 25">
|
||||
<translatableAttribute id="caption">Enabled Mods</translatableAttribute>
|
||||
</object>
|
||||
|
||||
<object name="modsEnabledList" style="ModernList" type="olist" size="0 25 96%-5 100%" font="sans-stroke-13" tooltip_style="pgToolTip">
|
||||
<action on="SelectionChange">showModDescription(this.name, g_modsEnabled);</action>
|
||||
<!-- List headers -->
|
||||
<def id="name" color="100 100 200" width="10%">
|
||||
<translatableAttribute id="heading">Name</translatableAttribute>
|
||||
</def>
|
||||
<def id="modVersion" color="128 128 128" width="5%">
|
||||
<translatableAttribute id="heading">Version</translatableAttribute>
|
||||
</def>
|
||||
<def id="modFolderName" color="100 100 200" width="15%">
|
||||
<translatableAttribute id="heading">(Folder)</translatableAttribute>
|
||||
</def>
|
||||
<def id="modLabel" color="0 60 0" width="18%">
|
||||
<translatableAttribute id="heading">Mod Label</translatableAttribute>
|
||||
</def>
|
||||
<def id="modType" color="0 128 128" width="12%">
|
||||
<translatableAttribute id="heading">Mod Type</translatableAttribute>
|
||||
</def>
|
||||
<def id="modDependencies" color="128 128 128" width="20%">
|
||||
<translatableAttribute id="heading">Dependencies</translatableAttribute>
|
||||
</def>
|
||||
<def id="modURL" color="128 128 128" width="20%">
|
||||
<translatableAttribute id="heading">Website</translatableAttribute>
|
||||
</def>
|
||||
</object>
|
||||
|
||||
<object type="button" style="ModernButtonRed" size="96% 23 100% 40%+12">
|
||||
<translatableAttribute id="caption">Up</translatableAttribute>
|
||||
<action on="Press">moveCurrItem(this.parent.name + "List", true);</action>
|
||||
</object>
|
||||
<object type="button" style="ModernButtonRed" size="96% 40%+12 100% 60%+10">
|
||||
<translatableAttribute id="caption">X</translatableAttribute>
|
||||
<action on="Press">disableMod();</action>
|
||||
</object>
|
||||
<object type="button" style="ModernButtonRed" size="96% 60%+10 100% 100%">
|
||||
<translatableAttribute id="caption">Down</translatableAttribute>
|
||||
<action on="Press">moveCurrItem(this.parent.name + "List", false);</action>
|
||||
</object>
|
||||
</object>
|
||||
|
||||
|
||||
<!-- BUTTONS -->
|
||||
<object type="button" style="ModernButtonRed" size="16 100%-44 200 100%-16">
|
||||
<translatableAttribute id="caption">Quit</translatableAttribute>
|
||||
<action on="Press">Engine.Exit();</action>
|
||||
</object>
|
||||
|
||||
<object type="button" style="ModernButtonRed" size="100%-576 100%-44 100%-392 100%-16">
|
||||
<translatableAttribute id="caption">Cancel</translatableAttribute>
|
||||
<action on="Press">closePage();</action>
|
||||
</object>
|
||||
|
||||
<object name="saveConfigurationButton" type="button" style="ModernButtonRed" size="100%-388 100%-44 100%-204 100%-16">
|
||||
<translatableAttribute id="caption">Save Configuration</translatableAttribute>
|
||||
<action on="Press">saveMods();</action>
|
||||
</object>
|
||||
|
||||
<object name="startModsButton" type="button" style="ModernButtonRed" size="100%-200 100%-44 100%-16 100%-16">
|
||||
<translatableAttribute id="caption">Start Mods</translatableAttribute>
|
||||
<action on="Press">startMods();</action>
|
||||
</object>
|
||||
</object>
|
||||
</objects>
|
15
binaries/data/mods/mod/gui/modmod/styles.xml
Normal file
15
binaries/data/mods/mod/gui/modmod/styles.xml
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<styles>
|
||||
<style name="ModmodScrollbar"
|
||||
buffer_zone="5"
|
||||
font="sans-13"
|
||||
scrollbar="true"
|
||||
scrollbar_style="ModernScrollBar"
|
||||
scroll_bottom="true"
|
||||
textcolor="white"
|
||||
textcolor_selected="gold"
|
||||
text_align="left"
|
||||
text_valign="center"
|
||||
/>
|
||||
</styles>
|
21
binaries/data/mods/mod/gui/page_modmod.xml
Normal file
21
binaries/data/mods/mod/gui/page_modmod.xml
Normal file
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<page>
|
||||
<include>common/modern/setup.xml</include>
|
||||
<include>common/modern/styles.xml</include>
|
||||
<include>common/modern/sprites.xml</include>
|
||||
|
||||
<include>common/setup.xml</include>
|
||||
<include>common/sprite1.xml</include>
|
||||
<include>common/styles.xml</include>
|
||||
<include>common/common_sprites.xml</include>
|
||||
<include>common/common_styles.xml</include>
|
||||
<include>common/init.xml</include>
|
||||
|
||||
<include>pregame/sprites.xml</include>
|
||||
<include>pregame/styles.xml</include>
|
||||
|
||||
<include>modmod/styles.xml</include>
|
||||
<include>modmod/modmod.xml</include>
|
||||
|
||||
<include>common/global.xml</include>
|
||||
</page>
|
4
binaries/data/mods/mod/gui/page_pregame.xml
Normal file
4
binaries/data/mods/mod/gui/page_pregame.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<page>
|
||||
<include>pregame/mainmenu.xml</include>
|
||||
</page>
|
4
binaries/data/mods/mod/gui/pregame/mainmenu.js
Normal file
4
binaries/data/mods/mod/gui/pregame/mainmenu.js
Normal file
@ -0,0 +1,4 @@
|
||||
function init()
|
||||
{
|
||||
Engine.SwitchGuiPage("page_modmod.xml", {});
|
||||
}
|
5
binaries/data/mods/mod/gui/pregame/mainmenu.xml
Normal file
5
binaries/data/mods/mod/gui/pregame/mainmenu.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<objects>
|
||||
<script file="gui/pregame/mainmenu.js"/>
|
||||
</objects>
|
@ -294,7 +294,6 @@
|
||||
type="button"
|
||||
size="0 0 100% 28"
|
||||
tooltip_style="pgToolTip"
|
||||
enabled="true"
|
||||
>
|
||||
<translatableAttribute id="caption">Options</translatableAttribute>
|
||||
<translatableAttribute id="tooltip">Adjust game settings.</translatableAttribute>
|
||||
@ -351,6 +350,18 @@
|
||||
]]>
|
||||
</action>
|
||||
</object>
|
||||
<object name="submenuModSelection"
|
||||
style="StoneButtonFancy"
|
||||
type="button"
|
||||
size="0 128 100% 156"
|
||||
tooltip_style="pgToolTip"
|
||||
>
|
||||
<translatableAttribute id="caption">Mod Selection</translatableAttribute>
|
||||
<translatableAttribute id="tooltip">Select mods to use.</translatableAttribute>
|
||||
<action on="Press">
|
||||
Engine.SwitchGuiPage("page_modmod.xml", {});
|
||||
</action>
|
||||
</object>
|
||||
</object>
|
||||
</object><!-- end of submenu -->
|
||||
|
||||
@ -450,7 +461,7 @@
|
||||
<translatableAttribute id="tooltip">Game options and scenario design tools.</translatableAttribute>
|
||||
<action on="Press">
|
||||
closeMenu();
|
||||
openMenu("submenuToolsAndOptions", (this.parent.size.top+this.size.top), (this.size.bottom-this.size.top), 4);
|
||||
openMenu("submenuToolsAndOptions", (this.parent.size.top+this.size.top), (this.size.bottom-this.size.top), 5);
|
||||
</action>
|
||||
</object>
|
||||
|
||||
|
9
binaries/data/mods/public/mod.json
Normal file
9
binaries/data/mods/public/mod.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"name": "0ad",
|
||||
"version": "0.0.17",
|
||||
"label": "0 A.D. Empires Ascendant",
|
||||
"url": "play0ad.com",
|
||||
"description": "A free, open-source, historical RTS game.",
|
||||
"dependencies": [],
|
||||
"type": "game"
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
|
||||
pyrogenesis=$(which pyrogenesis 2> /dev/null)
|
||||
if [ -x "$pyrogenesis" ] ; then
|
||||
"$pyrogenesis" "$@"
|
||||
"$pyrogenesis" -mod=public "$@"
|
||||
else
|
||||
echo "Error: pyrogenesis not found in ($PATH)"
|
||||
exit 1
|
||||
|
@ -52,6 +52,7 @@
|
||||
#include "ps/SavedGame.h"
|
||||
#include "ps/scripting/JSInterface_ConfigDB.h"
|
||||
#include "ps/scripting/JSInterface_Console.h"
|
||||
#include "ps/scripting/JSInterface_Mod.h"
|
||||
#include "ps/scripting/JSInterface_VFS.h"
|
||||
#include "ps/UserReport.h"
|
||||
#include "ps/GameSetup/Atlas.h"
|
||||
@ -762,11 +763,11 @@ int GetFps(ScriptInterface::CxPrivate* UNUSED(pCxPrivate))
|
||||
|
||||
CScriptVal GetGUIObjectByName(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), CStr name)
|
||||
{
|
||||
IGUIObject* guiObj = g_GUI->FindObjectByName(name);
|
||||
if (guiObj)
|
||||
return OBJECT_TO_JSVAL(guiObj->GetJSObject());
|
||||
else
|
||||
return JSVAL_VOID;
|
||||
IGUIObject* guiObj = g_GUI->FindObjectByName(name);
|
||||
if (guiObj)
|
||||
return OBJECT_TO_JSVAL(guiObj->GetJSObject());
|
||||
else
|
||||
return JSVAL_VOID;
|
||||
}
|
||||
|
||||
// Return the date/time at which the current executable was compiled.
|
||||
@ -909,6 +910,7 @@ void GuiScriptingInit(ScriptInterface& scriptInterface)
|
||||
JSI_Renderer::RegisterScriptFunctions(scriptInterface);
|
||||
JSI_Console::RegisterScriptFunctions(scriptInterface);
|
||||
JSI_ConfigDB::RegisterScriptFunctions(scriptInterface);
|
||||
JSI_Mod::RegisterScriptFunctions(scriptInterface);
|
||||
JSI_Sound::RegisterScriptFunctions(scriptInterface);
|
||||
JSI_L10n::RegisterScriptFunctions(scriptInterface);
|
||||
|
||||
|
@ -412,8 +412,9 @@ std::vector<CStr>& GetMods(const CmdLineArgs& args, int flags)
|
||||
}
|
||||
|
||||
g_modsLoaded = args.GetMultiple("mod");
|
||||
// TODO: It would be nice to remove this hard-coding of public
|
||||
// TODO: It would be nice to remove this hard-coding of public (remove it once mod is standalone)
|
||||
g_modsLoaded.insert(g_modsLoaded.begin(), "public");
|
||||
g_modsLoaded.insert(g_modsLoaded.begin(), "mod");
|
||||
|
||||
// Add the user mod if not explicitly disabled or we have a dev copy so
|
||||
// that saved files end up in version control and not in the user mod.
|
||||
|
128
source/ps/scripting/JSInterface_Mod.cpp
Normal file
128
source/ps/scripting/JSInterface_Mod.cpp
Normal file
@ -0,0 +1,128 @@
|
||||
/* Copyright (C) 2014 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "scriptinterface/ScriptInterface.h"
|
||||
#include "scriptinterface/ScriptVal.h"
|
||||
|
||||
#include "lib/file/file_system.h"
|
||||
#include "lib/file/vfs/vfs.h"
|
||||
#include "lib/utf8.h"
|
||||
#include "ps/Filesystem.h"
|
||||
#include "ps/GameSetup/GameSetup.h"
|
||||
#include "ps/GameSetup/Paths.h"
|
||||
#include "ps/Mod.h"
|
||||
#include "ps/scripting/JSInterface_Mod.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
extern void restart_engine();
|
||||
|
||||
/**
|
||||
* Returns a JS object containing a listing of available mods that
|
||||
* have a modname.json file in their modname folder. The returned
|
||||
* object looks like { modname1: json1, modname2: json2, ... } where
|
||||
* jsonN is the content of the modnameN/modnameN.json file as a JS
|
||||
* object.
|
||||
*
|
||||
* @return JS object with available mods as the keys of the modname.json
|
||||
* properties.
|
||||
*/
|
||||
CScriptVal JSI_Mod::GetAvailableMods(ScriptInterface::CxPrivate* pCxPrivate)
|
||||
{
|
||||
ScriptInterface* scriptInterface = pCxPrivate->pScriptInterface;
|
||||
JSContext* cx = scriptInterface->GetContext();
|
||||
JSAutoRequest rq(cx);
|
||||
JS::RootedObject obj(cx, JS_NewObject(cx, NULL, NULL, NULL));
|
||||
|
||||
const Paths paths(g_args);
|
||||
|
||||
// loop over all possible paths
|
||||
OsPath modPath = paths.RData()/"mods";
|
||||
OsPath modUserPath = paths.UserData()/"mods";
|
||||
|
||||
DirectoryNames modDirs;
|
||||
DirectoryNames modDirsUser;
|
||||
|
||||
GetDirectoryEntries(modPath, NULL, &modDirs);
|
||||
// Sort modDirs so that we can do a fast lookup below
|
||||
std::sort(modDirs.begin(), modDirs.end());
|
||||
|
||||
PIVFS vfs = CreateVfs(1); // No cache needed; TODO but 0 crashes
|
||||
|
||||
for (DirectoryNames::iterator iter = modDirs.begin(); iter != modDirs.end(); ++iter)
|
||||
{
|
||||
vfs->Clear();
|
||||
if (vfs->Mount(L"", modPath / *iter, VFS_MOUNT_MUST_EXIST) < 0)
|
||||
continue;
|
||||
|
||||
CVFSFile modinfo;
|
||||
if (modinfo.Load(vfs, L"mod.json", false) != PSRETURN_OK)
|
||||
continue;
|
||||
|
||||
JS::RootedValue json(cx);
|
||||
scriptInterface->ParseJSON(modinfo.GetAsString(), &json);
|
||||
|
||||
// Valid mod, add it to our structure
|
||||
JS_SetProperty(cx, obj, utf8_from_wstring(iter->string()).c_str(), json.address());
|
||||
}
|
||||
|
||||
GetDirectoryEntries(modUserPath, NULL, &modDirsUser);
|
||||
bool dev = InDevelopmentCopy();
|
||||
|
||||
for (DirectoryNames::iterator iter = modDirsUser.begin(); iter != modDirsUser.end(); ++iter)
|
||||
{
|
||||
// If we are in a dev copy we do not mount mods in the user mod folder that
|
||||
// are already present in the mod folder, thus we skip those here.
|
||||
if (dev && std::binary_search(modDirs.begin(), modDirs.end(), *iter))
|
||||
continue;
|
||||
|
||||
vfs->Clear();
|
||||
if (vfs->Mount(L"", modUserPath / *iter, VFS_MOUNT_MUST_EXIST) < 0)
|
||||
continue;
|
||||
|
||||
CVFSFile modinfo;
|
||||
if (modinfo.Load(vfs, L"mod.json", false) != PSRETURN_OK)
|
||||
continue;
|
||||
|
||||
JS::RootedValue json(cx);
|
||||
scriptInterface->ParseJSON(modinfo.GetAsString(), &json);
|
||||
|
||||
// Valid mod, add it to our structure
|
||||
JS_SetProperty(cx, obj, utf8_from_wstring(iter->string()).c_str(), json.address());
|
||||
}
|
||||
|
||||
return JS::ObjectValue(*obj);
|
||||
}
|
||||
|
||||
void JSI_Mod::RestartEngine(ScriptInterface::CxPrivate* UNUSED(pCxPrivate))
|
||||
{
|
||||
restart_engine();
|
||||
}
|
||||
|
||||
void JSI_Mod::SetMods(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), std::vector<CStr> mods)
|
||||
{
|
||||
g_modsLoaded = mods;
|
||||
}
|
||||
|
||||
void JSI_Mod::RegisterScriptFunctions(ScriptInterface& scriptInterface)
|
||||
{
|
||||
scriptInterface.RegisterFunction<CScriptVal, &JSI_Mod::GetAvailableMods>("GetAvailableMods");
|
||||
scriptInterface.RegisterFunction<void, &JSI_Mod::RestartEngine>("RestartEngine");
|
||||
scriptInterface.RegisterFunction<void, std::vector<CStr>, &JSI_Mod::SetMods>("SetMods");
|
||||
}
|
32
source/ps/scripting/JSInterface_Mod.h
Normal file
32
source/ps/scripting/JSInterface_Mod.h
Normal file
@ -0,0 +1,32 @@
|
||||
/* Copyright (C) 2014 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_JSI_MOD
|
||||
#define INCLUDED_JSI_MOD
|
||||
|
||||
class ScriptInterface;
|
||||
class CScriptVal;
|
||||
|
||||
namespace JSI_Mod
|
||||
{
|
||||
void RegisterScriptFunctions(ScriptInterface& scriptInterface);
|
||||
CScriptVal GetAvailableMods(ScriptInterface::CxPrivate* pCxPrivate);
|
||||
void RestartEngine(ScriptInterface::CxPrivate* pCxPrivate);
|
||||
void SetMods(ScriptInterface::CxPrivate* pCxPrivate, std::vector<CStr> mods);
|
||||
}
|
||||
|
||||
#endif
|
6
source/tools/dist/0ad.nsi
vendored
6
source/tools/dist/0ad.nsi
vendored
@ -58,6 +58,7 @@
|
||||
!insertmacro MUI_PAGE_INSTFILES
|
||||
|
||||
!define MUI_FINISHPAGE_RUN $INSTDIR\binaries\system\pyrogenesis.exe
|
||||
!define MUI_FINISHPAGE_RUN_PARAMETERS "-mod=public"
|
||||
!insertmacro MUI_PAGE_FINISH
|
||||
|
||||
!insertmacro MUI_UNPAGE_CONFIRM
|
||||
@ -80,6 +81,8 @@ Section "!Game and data files" GameSection
|
||||
|
||||
SetOutPath "$INSTDIR\binaries\data\mods\public"
|
||||
File "${CHECKOUTPATH}\binaries\data\mods\public\public.zip"
|
||||
SetOutPath "$INSTDIR\binaries\data\mods\mod"
|
||||
File "${CHECKOUTPATH}\binaries\data\mods\mod\mod.zip"
|
||||
|
||||
;Store installation folder
|
||||
WriteRegStr SHCTX "Software\0 A.D." "" $INSTDIR
|
||||
@ -106,7 +109,8 @@ Section "!Game and data files" GameSection
|
||||
;Create shortcuts
|
||||
CreateDirectory "$SMPROGRAMS\$StartMenuFolder"
|
||||
SetOutPath "$INSTDIR\binaries\system" ;Set working directory of shortcuts
|
||||
CreateShortCut "$SMPROGRAMS\$StartMenuFolder\0 A.D..lnk" "$INSTDIR\binaries\system\pyrogenesis.exe" ""
|
||||
CreateShortCut "$SMPROGRAMS\$StartMenuFolder\0 A.D..lnk" "$INSTDIR\binaries\system\pyrogenesis.exe" "-mod=public"
|
||||
CreateShortCut "$SMPROGRAMS\$StartMenuFolder\Pyrogenesis mod selector.lnk" "$INSTDIR\binaries\system\pyrogenesis.exe" ""
|
||||
CreateShortCut "$SMPROGRAMS\$StartMenuFolder\Map editor.lnk" "$INSTDIR\binaries\system\pyrogenesis.exe" "-editor" "$INSTDIR\binaries\data\tools\atlas\icons\ScenarioEditor.ico"
|
||||
SetOutPath "$INSTDIR"
|
||||
CreateShortCut "$SMPROGRAMS\$StartMenuFolder\Open logs folder.lnk" "$INSTDIR\OpenLogsFolder.bat"
|
||||
|
6
source/tools/dist/build.sh
vendored
6
source/tools/dist/build.sh
vendored
@ -32,8 +32,10 @@ echo L\"${SVNREV}-release\" > export-win32/build/svn_revision/svn_revision.txt
|
||||
# Package the mod data
|
||||
# (The platforms differ only in line endings, so just do the Unix one instead of
|
||||
# generating two needlessly inconsistent packages)
|
||||
${EXE} -archivebuild=export-unix/binaries/data/mods/public -archivebuild-output=export-unix/binaries/data/mods/public/public.zip
|
||||
${EXE} -mod=mod -archivebuild=export-unix/binaries/data/mods/public -archivebuild-output=export-unix/binaries/data/mods/public/public.zip
|
||||
cp export-unix/binaries/data/mods/public/public.zip export-win32/binaries/data/mods/public/public.zip
|
||||
${EXE} -archivebuild=export-unix/binaries/data/mods/mod -archivebuild-output=export-unix/binaries/data/mods/public/mod/mod.zip
|
||||
cp export-unix/binaries/data/mods/mod/mod.zip export-win32/binaries/data/mods/mod/mod.zip
|
||||
|
||||
# Collect the relevant files
|
||||
ln -Tsf export-unix ${PREFIX}
|
||||
@ -44,7 +46,7 @@ tar cf $PREFIX-unix-build.tar \
|
||||
${PREFIX}/{source,build,libraries/source,binaries/system/readme.txt,binaries/data/l10n,binaries/data/tests,binaries/data/mods/_test.*,*.txt}
|
||||
tar cf $PREFIX-unix-data.tar \
|
||||
--exclude='binaries/data/config/dev.cfg' \
|
||||
${PREFIX}/binaries/data/{config,mods/public/public.zip,tools}
|
||||
${PREFIX}/binaries/data/{config,mods/mod/mod.zip,mods/public/public.zip,tools}
|
||||
# TODO: ought to include generated docs in here, perhaps?
|
||||
|
||||
# Compress
|
||||
|
Loading…
Reference in New Issue
Block a user