Rewrite developer overlay to use class syntax, one class per checkbox, a class for the EntityState overlay and TimeWarp debug feature, refs #5387.
Using 22 classes instead of 1 class (refs 2bcf4f678b/D1928) leverages more benefit of the paradigm. In particular it means the checkboxes can own the EntityState and TimeWarp helpers and the DeveloperOverlay itself can remain independent. Improve performance by 200 microseconds per turn by unsubscribing from onSimulationUpdate when the developer overlay is not opened, refse3f43f6352
/ D2378. Move TimeWarp from input.js from8ddef2fee0
to independent class using hotkey release event from78bc56f33e
, refs #3194. Differential Revision: https://code.wildfiregames.com/D2383 This was SVN commit r23081.
This commit is contained in:
parent
6ec5855136
commit
96a6a136b6
@ -1,259 +0,0 @@
|
||||
function DeveloperOverlay(playerViewControl)
|
||||
{
|
||||
this.commandHeight = 20;
|
||||
this.displayState = false;
|
||||
this.timeWarp = false;
|
||||
this.controlAll = false;
|
||||
this.playerViewControl = playerViewControl;
|
||||
Engine.GetGUIObjectByName("devCommandsOverlay").onPress = this.toggle;
|
||||
this.layout();
|
||||
|
||||
registerSimulationUpdateHandler(this.update.bind(this));
|
||||
registerEntitySelectionChangeHandler(this.update.bind(this));
|
||||
}
|
||||
|
||||
DeveloperOverlay.prototype.getCommands = function() {
|
||||
return [
|
||||
{
|
||||
"label": translate("Control all units"),
|
||||
"onPress": checked => {
|
||||
Engine.PostNetworkCommand({
|
||||
"type": "control-all",
|
||||
"flag": checked
|
||||
});
|
||||
},
|
||||
"checked": () => this.controlAll,
|
||||
},
|
||||
{
|
||||
"label": translate("Change perspective"),
|
||||
"onPress": checked => {
|
||||
this.playerViewControl.setChangePerspective(checked);
|
||||
},
|
||||
},
|
||||
{
|
||||
"label": translate("Display selection state"),
|
||||
"onPress": checked => {
|
||||
this.displayState = checked;
|
||||
this.update();
|
||||
},
|
||||
},
|
||||
{
|
||||
"label": translate("Pathfinder overlay"),
|
||||
"onPress": checked => {
|
||||
Engine.GuiInterfaceCall("SetPathfinderDebugOverlay", checked);
|
||||
},
|
||||
},
|
||||
{
|
||||
"label": translate("Obstruction overlay"),
|
||||
"onPress": checked => {
|
||||
Engine.GuiInterfaceCall("SetObstructionDebugOverlay", checked);
|
||||
},
|
||||
},
|
||||
{
|
||||
"label": translate("Unit motion overlay"),
|
||||
"onPress": checked => {
|
||||
g_Selection.SetMotionDebugOverlay(checked);
|
||||
},
|
||||
},
|
||||
{
|
||||
"label": translate("Range overlay"),
|
||||
"onPress": checked => {
|
||||
Engine.GuiInterfaceCall("SetRangeDebugOverlay", checked);
|
||||
},
|
||||
},
|
||||
{
|
||||
"label": translate("Bounding box overlay"),
|
||||
"onPress": checked => {
|
||||
Engine.SetBoundingBoxDebugOverlay(checked);
|
||||
},
|
||||
},
|
||||
{
|
||||
"label": translate("Restrict camera"),
|
||||
"onPress": checked => {
|
||||
Engine.GameView_SetConstrainCameraEnabled(checked);
|
||||
},
|
||||
"checked": () => Engine.GameView_GetConstrainCameraEnabled(),
|
||||
},
|
||||
{
|
||||
"label": translate("Reveal map"),
|
||||
"onPress": checked => {
|
||||
Engine.PostNetworkCommand({
|
||||
"type": "reveal-map",
|
||||
"enable": checked
|
||||
});
|
||||
},
|
||||
"checked": () => Engine.GuiInterfaceCall("IsMapRevealed"),
|
||||
},
|
||||
{
|
||||
"label": translate("Enable time warp"),
|
||||
"onPress": checked => {
|
||||
this.timeWarp = checked;
|
||||
if (checked)
|
||||
messageBox(
|
||||
500, 250,
|
||||
translate("Note: time warp mode is a developer option, and not intended for use over long periods of time. Using it incorrectly may cause the game to run out of memory or crash."),
|
||||
translate("Time warp mode"));
|
||||
Engine.EnableTimeWarpRecording(checked ? 10 : 0);
|
||||
},
|
||||
},
|
||||
{
|
||||
"label": translate("Promote selected units"),
|
||||
"onPress": checked => {
|
||||
Engine.PostNetworkCommand({
|
||||
"type": "promote",
|
||||
"entities": g_Selection.toList()
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
"label": translate("Hierarchical pathfinder overlay"),
|
||||
"onPress": checked => {
|
||||
Engine.GuiInterfaceCall("SetPathfinderHierDebugOverlay", checked);
|
||||
},
|
||||
},
|
||||
{
|
||||
"label": translate("Enable culling"),
|
||||
"onPress": checked => {
|
||||
Engine.GameView_SetCullingEnabled(checked);
|
||||
},
|
||||
"checked": () => Engine.GameView_GetCullingEnabled(),
|
||||
},
|
||||
{
|
||||
"label": translate("Lock cull camera"),
|
||||
"onPress": checked => {
|
||||
Engine.GameView_SetLockCullCameraEnabled(checked);
|
||||
},
|
||||
"checked": () => Engine.GameView_GetLockCullCameraEnabled(),
|
||||
},
|
||||
{
|
||||
"label": translate("Display camera frustum"),
|
||||
"onPress": checked => {
|
||||
Engine.Renderer_SetDisplayFrustumEnabled(checked);
|
||||
},
|
||||
"checked": () => Engine.Renderer_GetDisplayFrustumEnabled(),
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
DeveloperOverlay.prototype.layout = function()
|
||||
{
|
||||
for (let body of Engine.GetGUIObjectByName("dev_commands").children)
|
||||
body.hidden = true;
|
||||
|
||||
let overlayHeight = 0;
|
||||
let commands = this.getCommands();
|
||||
for (let i = 0; i < commands.length; ++i)
|
||||
{
|
||||
let command = commands[i];
|
||||
|
||||
let body = Engine.GetGUIObjectByName("dev_command[" + i + "]");
|
||||
let bodySize = body.size;
|
||||
bodySize.top = i * this.commandHeight;
|
||||
bodySize.bottom = bodySize.top + this.commandHeight;
|
||||
body.size = bodySize;
|
||||
body.hidden = false;
|
||||
|
||||
let label = Engine.GetGUIObjectByName("dev_command_label[" + i + "]");
|
||||
label.caption = command.label;
|
||||
|
||||
let checkbox = Engine.GetGUIObjectByName("dev_command_checkbox[" + i + "]");
|
||||
checkbox.onPress = function() {
|
||||
command.onPress(checkbox.checked);
|
||||
if (command.checked)
|
||||
checkbox.checked = command.checked();
|
||||
};
|
||||
|
||||
overlayHeight += this.commandHeight;
|
||||
}
|
||||
|
||||
let overlay = Engine.GetGUIObjectByName("devCommandsOverlay");
|
||||
let overlaySize = overlay.size;
|
||||
overlaySize.bottom = overlaySize.top + overlayHeight;
|
||||
overlay.size = overlaySize;
|
||||
|
||||
this.updateValues();
|
||||
};
|
||||
|
||||
DeveloperOverlay.prototype.updateValues = function()
|
||||
{
|
||||
this.getCommands().forEach((command, i) => {
|
||||
let checkbox = Engine.GetGUIObjectByName("dev_command_checkbox[" + i + "]");
|
||||
if (command.checked)
|
||||
checkbox.checked = command.checked();
|
||||
});
|
||||
};
|
||||
|
||||
DeveloperOverlay.prototype.toggle = function()
|
||||
{
|
||||
if (!g_GameAttributes.settings.CheatsEnabled && !g_IsReplay)
|
||||
return;
|
||||
|
||||
let overlay = Engine.GetGUIObjectByName("devCommandsOverlay");
|
||||
overlay.hidden = !overlay.hidden;
|
||||
|
||||
let message = overlay.hidden ?
|
||||
markForTranslation("The Developer Overlay was closed.") :
|
||||
markForTranslation("The Developer Overlay was opened.");
|
||||
|
||||
// Only players can send the simulation chat command
|
||||
if (Engine.GetPlayerID() == -1)
|
||||
g_Chat.submitChat(message);
|
||||
else
|
||||
Engine.PostNetworkCommand({
|
||||
"type": "aichat",
|
||||
"message": message,
|
||||
"translateMessage": true,
|
||||
"translateParameters": [],
|
||||
"parameters": {}
|
||||
});
|
||||
};
|
||||
|
||||
DeveloperOverlay.prototype.update = function()
|
||||
{
|
||||
let playerState = g_SimState.players[g_ViewedPlayer];
|
||||
this.controlAll = playerState ? playerState.controlsAll : false;
|
||||
|
||||
this.updateValues();
|
||||
this.updateEntityState();
|
||||
}
|
||||
|
||||
DeveloperOverlay.prototype.updateEntityState = function()
|
||||
{
|
||||
let debug = Engine.GetGUIObjectByName("debugEntityState");
|
||||
|
||||
if (!this.displayState)
|
||||
{
|
||||
debug.hidden = true;
|
||||
return;
|
||||
}
|
||||
|
||||
debug.hidden = false;
|
||||
|
||||
let conciseSimState = clone(GetSimState());
|
||||
conciseSimState.players = "<<<omitted>>>";
|
||||
let text = "simulation: " + uneval(conciseSimState);
|
||||
|
||||
let selection = g_Selection.toList();
|
||||
if (selection.length)
|
||||
{
|
||||
let entState = GetEntityState(selection[0]);
|
||||
if (entState)
|
||||
{
|
||||
let template = GetTemplateData(entState.template);
|
||||
text += "\n\nentity: {\n";
|
||||
for (let k in entState)
|
||||
text += " " + k + ":" + uneval(entState[k]) + "\n";
|
||||
text += "}\n\ntemplate: " + uneval(template);
|
||||
}
|
||||
}
|
||||
|
||||
debug.caption = text.replace(/\[/g, "\\[");
|
||||
};
|
||||
|
||||
DeveloperOverlay.prototype.isTimeWarpEnabled = function() {
|
||||
return this.timeWarp;
|
||||
};
|
||||
|
||||
DeveloperOverlay.prototype.isControlAll = function() {
|
||||
return this.controlAll;
|
||||
};
|
@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<object
|
||||
name="devCommandsOverlay"
|
||||
type="image"
|
||||
sprite="sessionOverlayBackground"
|
||||
size="100%-250 50%-200 100%-8 50%"
|
||||
z="40"
|
||||
hidden="true"
|
||||
hotkey="session.devcommands.toggle"
|
||||
>
|
||||
<object name="dev_commands">
|
||||
<repeat count="16">
|
||||
<object name="dev_command[n]" size="0 0 100% 0">
|
||||
<object name="dev_command_label[n]" size="0 0 100%-26 100%" type="text" style="devCommandsText"/>
|
||||
<object name="dev_command_checkbox[n]" size="100%-24 1 100% 100%" type="checkbox" style="ModernTickBox"/>
|
||||
</object>
|
||||
</repeat>
|
||||
</object>
|
||||
</object>
|
@ -0,0 +1,68 @@
|
||||
/**
|
||||
* This class stores the checkboxes that are part of the developer overlay.
|
||||
* These checkboxes may own their own helper class instances, such as the EntityState or TimeWarp feature.
|
||||
*/
|
||||
class DeveloperOverlay
|
||||
{
|
||||
constructor(playerViewControl, selection)
|
||||
{
|
||||
this.devCommandsOverlay = Engine.GetGUIObjectByName("devCommandsOverlay");
|
||||
this.devCommandsOverlay.onPress = this.toggle.bind(this);
|
||||
|
||||
this.checkBoxes = this.getCheckboxNames().map((name, i) =>
|
||||
new DeveloperOverlayCheckbox(
|
||||
new DeveloperOverlayCheckboxes.prototype[name](playerViewControl, selection),
|
||||
i));
|
||||
|
||||
this.resize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Mods may overwrite this to change the order.
|
||||
*/
|
||||
getCheckboxNames()
|
||||
{
|
||||
return Object.keys(DeveloperOverlayCheckboxes.prototype);
|
||||
}
|
||||
|
||||
toggle()
|
||||
{
|
||||
if (g_IsNetworked && !g_GameAttributes.settings.CheatsEnabled)
|
||||
return;
|
||||
|
||||
this.devCommandsOverlay.hidden = !this.devCommandsOverlay.hidden;
|
||||
this.sendNotification();
|
||||
this.checkBoxes.forEach(checkbox => {
|
||||
checkbox.setHidden(this.devCommandsOverlay.hidden);
|
||||
});
|
||||
}
|
||||
|
||||
sendNotification()
|
||||
{
|
||||
let message = this.devCommandsOverlay.hidden ? this.CloseNotification : this.OpenNotification;
|
||||
|
||||
// Only players can send the simulation chat command
|
||||
if (Engine.GetPlayerID() == -1)
|
||||
g_Chat.submitChat(message);
|
||||
else
|
||||
Engine.PostNetworkCommand({
|
||||
"type": "aichat",
|
||||
"message": message,
|
||||
"translateMessage": true,
|
||||
"translateParameters": [],
|
||||
"parameters": {}
|
||||
});
|
||||
}
|
||||
|
||||
resize()
|
||||
{
|
||||
let size = this.devCommandsOverlay.size;
|
||||
size.bottom =
|
||||
size.top +
|
||||
this.checkBoxes.reduce((height, checkbox) => height + checkbox.getHeight(), 0);
|
||||
this.devCommandsOverlay.size = size;
|
||||
}
|
||||
}
|
||||
|
||||
DeveloperOverlay.prototype.OpenNotification = markForTranslation("The Developer Overlay was opened.");
|
||||
DeveloperOverlay.prototype.CloseNotification = markForTranslation("The Developer Overlay was closed.");
|
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<object
|
||||
name="devCommandsOverlay"
|
||||
type="image"
|
||||
sprite="sessionOverlayBackground"
|
||||
size="100%-250 50%-200 100%-8 50%"
|
||||
z="40"
|
||||
hidden="true"
|
||||
hotkey="session.devcommands.toggle"
|
||||
>
|
||||
<repeat count="20">
|
||||
<object name="dev_command[n]" size="0 0 100% 20" hidden="true">
|
||||
<object name="dev_command_label[n]" size="0 0 100%-26 100%" type="text" style="devCommandsText"/>
|
||||
<object name="dev_command_checkbox[n]" size="100%-24 1 100% 100%" type="checkbox" style="ModernTickBox"/>
|
||||
</object>
|
||||
</repeat>
|
||||
</object>
|
@ -0,0 +1,63 @@
|
||||
/**
|
||||
* This class sets up a checkbox in the developer overlay and assigns its specific handler.
|
||||
*/
|
||||
class DeveloperOverlayCheckbox
|
||||
{
|
||||
constructor(handler, i)
|
||||
{
|
||||
this.handler = handler;
|
||||
|
||||
this.label = Engine.GetGUIObjectByName("dev_command_label[" + i + "]");
|
||||
this.label.caption = this.handler.label();
|
||||
|
||||
this.checkbox = Engine.GetGUIObjectByName("dev_command_checkbox[" + i + "]");
|
||||
this.checkbox.onPress = this.onPress.bind(this);
|
||||
|
||||
this.body = Engine.GetGUIObjectByName("dev_command[" + i + "]");
|
||||
this.resize(i);
|
||||
|
||||
this.updater = this.update.bind(this);
|
||||
|
||||
if (this.handler.checked)
|
||||
registerPlayersInitHandler(this.updater);
|
||||
}
|
||||
|
||||
onPress()
|
||||
{
|
||||
this.handler.onPress(this.checkbox.checked);
|
||||
|
||||
if (this.handler.checked)
|
||||
this.update();
|
||||
}
|
||||
|
||||
update()
|
||||
{
|
||||
this.checkbox.checked = this.handler.checked();
|
||||
}
|
||||
|
||||
setHidden(hidden)
|
||||
{
|
||||
if (!this.handler.checked)
|
||||
return;
|
||||
|
||||
if (hidden)
|
||||
unregisterSimulationUpdateHandler(this.updater);
|
||||
else
|
||||
registerSimulationUpdateHandler(this.updater);
|
||||
}
|
||||
|
||||
getHeight()
|
||||
{
|
||||
return this.body.size.bottom - this.body.size.top;
|
||||
}
|
||||
|
||||
resize(i)
|
||||
{
|
||||
let size = this.body.size;
|
||||
let height = size.bottom;
|
||||
size.top = height * i;
|
||||
size.bottom = height * (i + 1);
|
||||
this.body.size = size;
|
||||
this.body.hidden = false;
|
||||
}
|
||||
}
|
@ -0,0 +1,277 @@
|
||||
/**
|
||||
* This class stores the handlers for the individual checkboxes available in the developer overlay.
|
||||
* Such a class must have label and onPress function.
|
||||
* If the class has a checked property, then that will be called every simulation update to
|
||||
* synchronize the state of the checkbox (only if the developer overaly is opened).
|
||||
*/
|
||||
class DeveloperOverlayCheckboxes
|
||||
{
|
||||
}
|
||||
|
||||
DeveloperOverlayCheckboxes.prototype.ControlAll = class
|
||||
{
|
||||
label()
|
||||
{
|
||||
return translate("Control all units");
|
||||
}
|
||||
|
||||
onPress(checked)
|
||||
{
|
||||
Engine.PostNetworkCommand({
|
||||
"type": "control-all",
|
||||
"flag": checked
|
||||
});
|
||||
}
|
||||
|
||||
checked()
|
||||
{
|
||||
let playerState = g_SimState.players[g_ViewedPlayer];
|
||||
return playerState ? playerState.controlsAll : false;
|
||||
}
|
||||
};
|
||||
|
||||
DeveloperOverlayCheckboxes.prototype.ChangePerspective = class
|
||||
{
|
||||
constructor(playerViewControl)
|
||||
{
|
||||
this.playerViewControl = playerViewControl;
|
||||
}
|
||||
|
||||
label()
|
||||
{
|
||||
return translate("Change perspective");
|
||||
}
|
||||
|
||||
onPress(checked)
|
||||
{
|
||||
this.playerViewControl.setChangePerspective(checked);
|
||||
}
|
||||
};
|
||||
|
||||
DeveloperOverlayCheckboxes.prototype.SelectionEntityState = class
|
||||
{
|
||||
constructor(playerViewControl, selection)
|
||||
{
|
||||
this.developerOverlayEntityState = new DeveloperOverlayEntityState(selection);
|
||||
}
|
||||
|
||||
label()
|
||||
{
|
||||
return translate("Display selection state");
|
||||
}
|
||||
|
||||
onPress(checked)
|
||||
{
|
||||
this.developerOverlayEntityState.setEnabled(checked);
|
||||
}
|
||||
};
|
||||
|
||||
DeveloperOverlayCheckboxes.prototype.PathfinderOverlay = class
|
||||
{
|
||||
label()
|
||||
{
|
||||
return translate("Pathfinder overlay");
|
||||
}
|
||||
|
||||
onPress(checked)
|
||||
{
|
||||
Engine.GuiInterfaceCall("SetPathfinderDebugOverlay", checked);
|
||||
}
|
||||
};
|
||||
|
||||
DeveloperOverlayCheckboxes.prototype.HierarchicalPathfinderOverlay = class
|
||||
{
|
||||
label()
|
||||
{
|
||||
return translate("Hierarchical pathfinder overlay");
|
||||
}
|
||||
|
||||
onPress(checked)
|
||||
{
|
||||
Engine.GuiInterfaceCall("SetPathfinderHierDebugOverlay", checked);
|
||||
}
|
||||
};
|
||||
|
||||
DeveloperOverlayCheckboxes.prototype.ObstructionOverlay = class
|
||||
{
|
||||
label()
|
||||
{
|
||||
return translate("Obstruction overlay");
|
||||
}
|
||||
|
||||
onPress(checked)
|
||||
{
|
||||
Engine.GuiInterfaceCall("SetObstructionDebugOverlay", checked);
|
||||
}
|
||||
};
|
||||
|
||||
DeveloperOverlayCheckboxes.prototype.UnitMotionOverlay = class
|
||||
{
|
||||
label()
|
||||
{
|
||||
return translate("Unit motion overlay");
|
||||
}
|
||||
|
||||
onPress(checked)
|
||||
{
|
||||
g_Selection.SetMotionDebugOverlay(checked);
|
||||
}
|
||||
};
|
||||
|
||||
DeveloperOverlayCheckboxes.prototype.RangeOverlay = class
|
||||
{
|
||||
label()
|
||||
{
|
||||
return translate("Range overlay");
|
||||
}
|
||||
|
||||
onPress(checked)
|
||||
{
|
||||
Engine.GuiInterfaceCall("SetRangeDebugOverlay", checked);
|
||||
}
|
||||
};
|
||||
|
||||
DeveloperOverlayCheckboxes.prototype.BoundingBoxOverlay = class
|
||||
{
|
||||
label()
|
||||
{
|
||||
return translate("Bounding box overlay");
|
||||
}
|
||||
|
||||
onPress(checked)
|
||||
{
|
||||
Engine.SetBoundingBoxDebugOverlay(checked);
|
||||
}
|
||||
};
|
||||
|
||||
DeveloperOverlayCheckboxes.prototype.RestrictCamera = class
|
||||
{
|
||||
label()
|
||||
{
|
||||
return translate("Restrict camera");
|
||||
}
|
||||
|
||||
onPress(checked)
|
||||
{
|
||||
Engine.GameView_SetConstrainCameraEnabled(checked);
|
||||
}
|
||||
|
||||
checked()
|
||||
{
|
||||
return Engine.GameView_GetConstrainCameraEnabled();
|
||||
}
|
||||
};
|
||||
|
||||
DeveloperOverlayCheckboxes.prototype.RevealMap = class
|
||||
{
|
||||
label()
|
||||
{
|
||||
return translate("Reveal map");
|
||||
}
|
||||
|
||||
onPress(checked)
|
||||
{
|
||||
Engine.PostNetworkCommand({
|
||||
"type": "reveal-map",
|
||||
"enable": checked
|
||||
});
|
||||
}
|
||||
|
||||
checked()
|
||||
{
|
||||
return Engine.GuiInterfaceCall("IsMapRevealed");
|
||||
}
|
||||
};
|
||||
|
||||
DeveloperOverlayCheckboxes.prototype.EnableTimeWarp = class
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
this.timeWarp = new TimeWarp();
|
||||
}
|
||||
|
||||
label()
|
||||
{
|
||||
return translate("Enable time warp");
|
||||
}
|
||||
|
||||
onPress(checked)
|
||||
{
|
||||
this.timeWarp.setEnabled(checked);
|
||||
}
|
||||
};
|
||||
|
||||
DeveloperOverlayCheckboxes.prototype.PromoteSelectedUnits = class
|
||||
{
|
||||
label()
|
||||
{
|
||||
return translate("Promote selected units");
|
||||
}
|
||||
|
||||
onPress(checked)
|
||||
{
|
||||
Engine.PostNetworkCommand({
|
||||
"type": "promote",
|
||||
"entities": g_Selection.toList()
|
||||
});
|
||||
}
|
||||
|
||||
checked()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
DeveloperOverlayCheckboxes.prototype.EnableCulling = class
|
||||
{
|
||||
label()
|
||||
{
|
||||
return translate("Enable culling");
|
||||
}
|
||||
|
||||
onPress(checked)
|
||||
{
|
||||
Engine.GameView_SetCullingEnabled(checked);
|
||||
}
|
||||
|
||||
checked()
|
||||
{
|
||||
return Engine.GameView_GetCullingEnabled();
|
||||
}
|
||||
};
|
||||
|
||||
DeveloperOverlayCheckboxes.prototype.LockCullCamera = class
|
||||
{
|
||||
label()
|
||||
{
|
||||
return translate("Lock cull camera");
|
||||
}
|
||||
|
||||
onPress(checked)
|
||||
{
|
||||
Engine.GameView_SetLockCullCameraEnabled(checked);
|
||||
}
|
||||
|
||||
checked()
|
||||
{
|
||||
return Engine.GameView_GetLockCullCameraEnabled();
|
||||
}
|
||||
};
|
||||
|
||||
DeveloperOverlayCheckboxes.prototype.DisplayCameraFrustum = class
|
||||
{
|
||||
label()
|
||||
{
|
||||
return translate("Display camera frustum");
|
||||
}
|
||||
|
||||
onPress(checked)
|
||||
{
|
||||
Engine.Renderer_SetDisplayFrustumEnabled(checked);
|
||||
}
|
||||
|
||||
checked()
|
||||
{
|
||||
return Engine.Renderer_GetDisplayFrustumEnabled();
|
||||
}
|
||||
};
|
@ -0,0 +1,51 @@
|
||||
/**
|
||||
* This class manages the developer overlay which displays the state of the first selected entity.
|
||||
*/
|
||||
class DeveloperOverlayEntityState
|
||||
{
|
||||
constructor(selection)
|
||||
{
|
||||
this.developerOverlayEntityState = Engine.GetGUIObjectByName("developerOverlayEntityState");
|
||||
this.selection = selection;
|
||||
this.updater = this.update.bind(this);
|
||||
}
|
||||
|
||||
setEnabled(enabled)
|
||||
{
|
||||
this.developerOverlayEntityState.hidden = !enabled;
|
||||
|
||||
if (enabled)
|
||||
{
|
||||
registerSimulationUpdateHandler(this.updater);
|
||||
registerEntitySelectionChangeHandler(this.updater);
|
||||
}
|
||||
else
|
||||
{
|
||||
unregisterSimulationUpdateHandler(this.updater);
|
||||
unregisterEntitySelectionChangeHandler(this.updater);
|
||||
}
|
||||
}
|
||||
|
||||
update()
|
||||
{
|
||||
let simState = clone(g_SimState);
|
||||
simState.players = "<<<omitted>>>";
|
||||
let text = "simulation: " + uneval(simState);
|
||||
|
||||
let selection = this.selection.toList();
|
||||
if (selection.length)
|
||||
{
|
||||
let entState = GetEntityState(selection[0]);
|
||||
if (entState)
|
||||
{
|
||||
let template = GetTemplateData(entState.template);
|
||||
text += "\n\nentity: {\n";
|
||||
for (let k in entState)
|
||||
text += " " + k + ":" + uneval(entState[k]) + "\n";
|
||||
text += "}\n\ntemplate: " + uneval(template);
|
||||
}
|
||||
}
|
||||
|
||||
this.developerOverlayEntityState.caption = text.replace(/\[/g, "\\[");
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<object name="developerOverlayEntityState"
|
||||
type="text"
|
||||
size="0 70 80% 100%"
|
||||
ghost="true"
|
||||
textcolor="yellow"
|
||||
font="mono-stroke-10"
|
||||
hidden="true"
|
||||
/>
|
@ -0,0 +1,66 @@
|
||||
/**
|
||||
* This class manages the timewarp hotkeys that allow jumping back in time and fast forwarding the game.
|
||||
*/
|
||||
class TimeWarp
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
this.enabled = false;
|
||||
|
||||
this.timewarpRewind = Engine.GetGUIObjectByName("timewarpRewind");
|
||||
this.timewarpRewind.onPress = this.rewind.bind(this);
|
||||
|
||||
this.timewarpFastForward = Engine.GetGUIObjectByName("timewarpFastForward");
|
||||
this.timewarpFastForward.onPress = this.fastForward.bind(this);
|
||||
this.timewarpFastForward.onRelease = this.resetSpeed.bind(this);
|
||||
}
|
||||
|
||||
setEnabled(enabled)
|
||||
{
|
||||
if (g_IsNetworked)
|
||||
return;
|
||||
|
||||
this.enabled = enabled;
|
||||
|
||||
if (enabled)
|
||||
messageBox(
|
||||
500, 250,
|
||||
translate(this.Description),
|
||||
translate(this.Title));
|
||||
|
||||
Engine.EnableTimeWarpRecording(enabled ? this.NumberTurns : 0);
|
||||
}
|
||||
|
||||
rewind()
|
||||
{
|
||||
if (this.enabled)
|
||||
Engine.RewindTimeWarp();
|
||||
}
|
||||
|
||||
fastForward()
|
||||
{
|
||||
if (this.enabled)
|
||||
Engine.SetSimRate(this.FastForwardSpeed);
|
||||
}
|
||||
|
||||
resetSpeed()
|
||||
{
|
||||
if (this.enabled)
|
||||
Engine.SetSimRate(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of turns between snapshots.
|
||||
*/
|
||||
TimeWarp.prototype.NumberTurns = 10;
|
||||
|
||||
/**
|
||||
* Gamespeed used while pressing the fast forward hotkey.
|
||||
*/
|
||||
TimeWarp.prototype.FastForwardSpeed = 20;
|
||||
|
||||
TimeWarp.prototype.Title = markForTranslation("Time warp mode");
|
||||
|
||||
TimeWarp.prototype.Description = markForTranslation(
|
||||
"Note: time warp mode is a developer option, and not intended for use over long periods of time. Using it incorrectly may cause the game to run out of memory or crash.");
|
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<object>
|
||||
<object name="timewarpRewind" hotkey="session.timewarp.rewind"/>
|
||||
<object name="timewarpFastForward" hotkey="session.timewarp.fastforward"/>
|
||||
</object>
|
@ -223,12 +223,7 @@ function determineAction(x, y, fromMinimap)
|
||||
return undefined;
|
||||
|
||||
// If the selection isn't friendly units, no action
|
||||
var allOwnedByPlayer = selection.every(ent => {
|
||||
var entState = GetEntityState(ent);
|
||||
return entState && entState.player == g_ViewedPlayer;
|
||||
});
|
||||
|
||||
if (!g_DeveloperOverlay.isControlAll() && !allOwnedByPlayer)
|
||||
if (!selection.every(canControlEntity))
|
||||
return undefined;
|
||||
|
||||
var target = undefined;
|
||||
@ -278,6 +273,19 @@ function determineAction(x, y, fromMinimap)
|
||||
return { "type": "none", "cursor": "", "target": target };
|
||||
}
|
||||
|
||||
function canControlEntity(ent)
|
||||
{
|
||||
let entState = GetEntityState(ent);
|
||||
if (!entState)
|
||||
return false;
|
||||
|
||||
if (entState.player == g_ViewedPlayer)
|
||||
return true;
|
||||
|
||||
let playerState = g_SimState.players[entState.player];
|
||||
return playerState && playerState.controlsAll;
|
||||
}
|
||||
|
||||
function tryPlaceBuilding(queued)
|
||||
{
|
||||
if (placementSupport.mode !== "building")
|
||||
@ -786,17 +794,6 @@ function handleInputAfterGui(ev)
|
||||
if (ev.hotkey === undefined)
|
||||
ev.hotkey = null;
|
||||
|
||||
// Handle the time-warp testing features, restricted to single-player
|
||||
if (!g_IsNetworked && g_DeveloperOverlay.isTimeWarpEnabled())
|
||||
{
|
||||
if (ev.type == "hotkeydown" && ev.hotkey == "session.timewarp.fastforward")
|
||||
Engine.SetSimRate(20.0);
|
||||
else if (ev.type == "hotkeyup" && ev.hotkey == "session.timewarp.fastforward")
|
||||
Engine.SetSimRate(1.0);
|
||||
else if (ev.type == "hotkeyup" && ev.hotkey == "session.timewarp.rewind")
|
||||
Engine.RewindTimeWarp();
|
||||
}
|
||||
|
||||
if (ev.hotkey == "session.highlightguarding")
|
||||
{
|
||||
g_ShowGuarding = (ev.type == "hotkeydown");
|
||||
|
@ -214,8 +214,10 @@ EntitySelection.prototype.update = function()
|
||||
{
|
||||
this.checkRenamedEntities();
|
||||
|
||||
let controlsAll = g_SimState.players[g_ViewedPlayer] && g_SimState.players[g_ViewedPlayer].controlsAll;
|
||||
let removeOwnerChanges = !g_IsObserver && !controlsAll && this.toList().length > 1;
|
||||
|
||||
let changed = false;
|
||||
let removeOwnerChanges = !g_IsObserver && !g_DeveloperOverlay.isControlAll() && this.toList().length > 1;
|
||||
|
||||
for (let ent in this.selected)
|
||||
{
|
||||
@ -377,6 +379,9 @@ EntitySelection.prototype.getFirstSelected = function()
|
||||
return undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* TODO: This array should not be recreated every call
|
||||
*/
|
||||
EntitySelection.prototype.toList = function()
|
||||
{
|
||||
let ents = [];
|
||||
|
@ -11,6 +11,7 @@ const g_VictoryDurations = prepareForDropdown(g_Settings && g_Settings.VictoryDu
|
||||
const g_VictoryConditions = g_Settings && g_Settings.VictoryConditions;
|
||||
|
||||
var g_Chat;
|
||||
var g_DeveloperOverlay;
|
||||
var g_DiplomacyColors;
|
||||
var g_DiplomacyDialog;
|
||||
var g_GameSpeedControl;
|
||||
@ -107,8 +108,6 @@ var g_ReplaySelectionData;
|
||||
*/
|
||||
var g_PlayerAssignments;
|
||||
|
||||
var g_DeveloperOverlay;
|
||||
|
||||
/**
|
||||
* Whether the entire UI should be hidden (useful for promotional screenshots).
|
||||
* Can be toggled with a hotkey.
|
||||
@ -134,22 +133,22 @@ var g_ResourceData = new Resources();
|
||||
* These handlers are called each time a new turn was simulated.
|
||||
* Use this as sparely as possible.
|
||||
*/
|
||||
var g_SimulationUpdateHandlers = [];
|
||||
var g_SimulationUpdateHandlers = new Set();
|
||||
|
||||
/**
|
||||
* These handlers are called after the player states have been initialized.
|
||||
*/
|
||||
var g_PlayersInitHandlers = [];
|
||||
var g_PlayersInitHandlers = new Set();
|
||||
|
||||
/**
|
||||
* These handlers are called when a player has been defeated or won the game.
|
||||
*/
|
||||
var g_PlayerFinishedHandlers = [];
|
||||
var g_PlayerFinishedHandlers = new Set();
|
||||
|
||||
/**
|
||||
* These events are fired whenever the player added or removed entities from the selection.
|
||||
*/
|
||||
var g_EntitySelectionChangeHandlers = [];
|
||||
var g_EntitySelectionChangeHandlers = new Set();
|
||||
|
||||
/**
|
||||
* These events are fired when the user has performed a hotkey assignment change.
|
||||
@ -281,7 +280,7 @@ function init(initData, hotloadData)
|
||||
g_PlayerViewControl.registerViewedPlayerChangeHandler(resetTemplates);
|
||||
|
||||
g_Chat = new Chat(g_PlayerViewControl);
|
||||
g_DeveloperOverlay = new DeveloperOverlay(g_PlayerViewControl);
|
||||
g_DeveloperOverlay = new DeveloperOverlay(g_PlayerViewControl, g_Selection);
|
||||
g_DiplomacyDialog = new DiplomacyDialog(g_PlayerViewControl, g_DiplomacyColors);
|
||||
g_GameSpeedControl = new GameSpeedControl(g_PlayerViewControl);
|
||||
g_MiniMapPanel = new MiniMapPanel(g_PlayerViewControl, g_DiplomacyColors, g_WorkerTypes);
|
||||
@ -323,22 +322,32 @@ function init(initData, hotloadData)
|
||||
|
||||
function registerPlayersInitHandler(handler)
|
||||
{
|
||||
g_PlayersInitHandlers.push(handler);
|
||||
g_PlayersInitHandlers.add(handler);
|
||||
}
|
||||
|
||||
function registerPlayersFinishedHandler(handler)
|
||||
{
|
||||
g_PlayerFinishedHandlers.push(handler);
|
||||
g_PlayerFinishedHandlers.add(handler);
|
||||
}
|
||||
|
||||
function registerSimulationUpdateHandler(handler)
|
||||
{
|
||||
g_SimulationUpdateHandlers.push(handler);
|
||||
g_SimulationUpdateHandlers.add(handler);
|
||||
}
|
||||
|
||||
function unregisterSimulationUpdateHandler(handler)
|
||||
{
|
||||
g_SimulationUpdateHandlers.delete(handler);
|
||||
}
|
||||
|
||||
function registerEntitySelectionChangeHandler(handler)
|
||||
{
|
||||
g_EntitySelectionChangeHandlers.push(handler);
|
||||
g_EntitySelectionChangeHandlers.add(handler);
|
||||
}
|
||||
|
||||
function unregisterEntitySelectionChangeHandler(handler)
|
||||
{
|
||||
g_EntitySelectionChangeHandlers.delete(handler);
|
||||
}
|
||||
|
||||
function registerHotkeyChangeHandler(handler)
|
||||
|
@ -5,6 +5,7 @@
|
||||
<script directory="gui/common/"/>
|
||||
<script directory="gui/session/"/>
|
||||
<script directory="gui/session/chat/"/>
|
||||
<script directory="gui/session/developer_overlay/"/>
|
||||
<script directory="gui/session/diplomacy/"/>
|
||||
<script directory="gui/session/diplomacy/playercontrols/"/>
|
||||
<script directory="gui/session/minimap/"/>
|
||||
@ -78,20 +79,11 @@
|
||||
<object name="chatText" size="3 1 100%-1 100%-1" type="text" style="chatPanelOverlay" ghost="true"/>
|
||||
</object>
|
||||
|
||||
<!-- Entity selection state text -->
|
||||
<object name="debugEntityState"
|
||||
type="text"
|
||||
size="0 70 80% 100%"
|
||||
ghost="true"
|
||||
textcolor="yellow"
|
||||
font="mono-stroke-10"
|
||||
/>
|
||||
|
||||
<include directory="gui/session/chat/"/>
|
||||
<include directory="gui/session/developer_overlay/"/>
|
||||
<include directory="gui/session/dialogs/"/>
|
||||
<include directory="gui/session/diplomacy/"/>
|
||||
<include directory="gui/session/objectives/"/>
|
||||
<include file="gui/session/developer_overlay.xml"/>
|
||||
<include file="gui/session/GameSpeedControl.xml"/>
|
||||
<include file="gui/session/TopPanel.xml"/>
|
||||
<include file="gui/session/trade/TradeDialog.xml"/>
|
||||
|
@ -1465,7 +1465,8 @@ function someCanPatrol(entities)
|
||||
*/
|
||||
function isUndeletable(entState)
|
||||
{
|
||||
if (g_DeveloperOverlay.isControlAll())
|
||||
let playerState = g_SimState.players[entState.player];
|
||||
if (playerState && playerState.controlsAll)
|
||||
return false;
|
||||
|
||||
if (entState.resourceSupply && entState.resourceSupply.killBeforeGather)
|
||||
|
Loading…
Reference in New Issue
Block a user