Compare commits
256 Commits
release-20
...
playtest-2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7bd7f4e56b | ||
|
|
9584c78500 | ||
|
|
bc7a9c14d0 | ||
|
|
c1eacc225d | ||
|
|
e56bbe367d | ||
|
|
6cf9939ab3 | ||
|
|
b2f3b8f2af | ||
|
|
80e897abfb | ||
|
|
d152d21338 | ||
|
|
f4e04ece12 | ||
|
|
e7a07ea9c3 | ||
|
|
f8e6245903 | ||
|
|
7c146a9d5d | ||
|
|
846286c988 | ||
|
|
ba25bc6df4 | ||
|
|
622f9bfe71 | ||
|
|
8df47f5a60 | ||
|
|
d2a0647085 | ||
|
|
0e750a3f25 | ||
|
|
0e6dbe28a8 | ||
|
|
cc0c45bceb | ||
|
|
af3e734561 | ||
|
|
1ac61c5e3e | ||
|
|
5d3622b79d | ||
|
|
b3ddf1ae86 | ||
|
|
17770631a2 | ||
|
|
05f6958286 | ||
|
|
bd9c748b17 | ||
|
|
6b40abb58c | ||
|
|
6d67ab2240 | ||
|
|
8b3512e2f1 | ||
|
|
5b71bee4c8 | ||
|
|
75e7124af0 | ||
|
|
9ad55d5e28 | ||
|
|
9e93edf336 | ||
|
|
5608756a24 | ||
|
|
ebca421856 | ||
|
|
22e61a5700 | ||
|
|
7306de3730 | ||
|
|
10ed3db71d | ||
|
|
04e05d9aed | ||
|
|
caae95f12e | ||
|
|
dfa14f16d3 | ||
|
|
8e007131c9 | ||
|
|
ed4c588701 | ||
|
|
d33806e932 | ||
|
|
e83838e9ff | ||
|
|
b77dcd476c | ||
|
|
836b3a598b | ||
|
|
967b16fc0e | ||
|
|
ee3437d0f6 | ||
|
|
e20c736e3f | ||
|
|
a98d20ea72 | ||
|
|
38486e8184 | ||
|
|
047a09bbbd | ||
|
|
d55e58ea1c | ||
|
|
17afe80a54 | ||
|
|
42bf568d80 | ||
|
|
50157c43de | ||
|
|
41988a1298 | ||
|
|
86058ec19f | ||
|
|
356c750b23 | ||
|
|
26cbb9d9c6 | ||
|
|
4a0b78c1e6 | ||
|
|
fcb7c845ba | ||
|
|
12f9c0bce9 | ||
|
|
47ed79b912 | ||
|
|
a265d11a5f | ||
|
|
8a96c5f7b5 | ||
|
|
5e5456191c | ||
|
|
aae7f56e7d | ||
|
|
3645b3ee13 | ||
|
|
e0f357390c | ||
|
|
9c3cb62838 | ||
|
|
14225b8e79 | ||
|
|
e01bf735d9 | ||
|
|
1904f8ced1 | ||
|
|
3caca8c323 | ||
|
|
dd7ce2d45e | ||
|
|
f793f4548b | ||
|
|
56675a61f5 | ||
|
|
3dd27fcb77 | ||
|
|
13d76f8e9c | ||
|
|
9a2cdcde11 | ||
|
|
155e7320cb | ||
|
|
750fd84494 | ||
|
|
924adc68a9 | ||
|
|
0f8d9d7fb3 | ||
|
|
801aa1156f | ||
|
|
aa0c14c214 | ||
|
|
8fcbb670d8 | ||
|
|
85a26ecdf7 | ||
|
|
480c5edd75 | ||
|
|
fdfa1ddf97 | ||
|
|
80caf1818b | ||
|
|
5c0cd50797 | ||
|
|
8129d5d7dc | ||
|
|
a77b7af5fd | ||
|
|
ecf41722c3 | ||
|
|
39b09780f6 | ||
|
|
98dec6dc8e | ||
|
|
50b1ba3acc | ||
|
|
c3fc7b98f3 | ||
|
|
f5b8b18d86 | ||
|
|
e7c61fac5c | ||
|
|
2640603f6c | ||
|
|
1a011276bf | ||
|
|
bc7cf09287 | ||
|
|
7762241653 | ||
|
|
9489196911 | ||
|
|
e32e060d37 | ||
|
|
5e3fce6820 | ||
|
|
6655b6ba6a | ||
|
|
0b4b003c10 | ||
|
|
380e7e8b20 | ||
|
|
9b3533abc0 | ||
|
|
1409016cbd | ||
|
|
4aa1fb4b86 | ||
|
|
40126c52e8 | ||
|
|
dd600d4590 | ||
|
|
532f420338 | ||
|
|
e25878e78d | ||
|
|
002cc4842a | ||
|
|
eac548ac8b | ||
|
|
3fc4d1b219 | ||
|
|
80e3b8be0d | ||
|
|
fa35f6caa4 | ||
|
|
526cf6059a | ||
|
|
1527e472b6 | ||
|
|
94f7c6db97 | ||
|
|
e3ddb8f757 | ||
|
|
d7d0d371c6 | ||
|
|
527c60daa7 | ||
|
|
c30050396a | ||
|
|
60a8acf4d4 | ||
|
|
5164c3cd7d | ||
|
|
6276e659cd | ||
|
|
298314626e | ||
|
|
0112bc4df7 | ||
|
|
c8dbed938a | ||
|
|
278f35e4aa | ||
|
|
dd38e45f2e | ||
|
|
3e08f9b1b1 | ||
|
|
8392a44314 | ||
|
|
d050d1a4b9 | ||
|
|
56598ce2ff | ||
|
|
2fb72155eb | ||
|
|
030bd4b28d | ||
|
|
b9c40ad3ce | ||
|
|
4490a90332 | ||
|
|
15d6facdb9 | ||
|
|
b80962b365 | ||
|
|
814c6a8713 | ||
|
|
eea89c1d33 | ||
|
|
9ec0367ecb | ||
|
|
f5fe1013ee | ||
|
|
c338d28d35 | ||
|
|
2f962452e5 | ||
|
|
10f5e68f7f | ||
|
|
1cde37f32b | ||
|
|
291899de8a | ||
|
|
cc70669f1a | ||
|
|
c568dfa486 | ||
|
|
ff7daf8727 | ||
|
|
fc72066ed2 | ||
|
|
253ccd6d9b | ||
|
|
01accaeb38 | ||
|
|
46c3bc09a1 | ||
|
|
2f0b7566e5 | ||
|
|
9b8ec714d2 | ||
|
|
5d408fe3c7 | ||
|
|
aa0b7bedf0 | ||
|
|
c5358f7c82 | ||
|
|
158d6e5647 | ||
|
|
e091781104 | ||
|
|
25582cb9f8 | ||
|
|
fece294cc6 | ||
|
|
c3501f68e3 | ||
|
|
c4ee5fbd41 | ||
|
|
9a54074b1b | ||
|
|
10e918c375 | ||
|
|
bbcad99fa7 | ||
|
|
c8198a1a1c | ||
|
|
8d5241f419 | ||
|
|
448b681c5b | ||
|
|
826f7a29b5 | ||
|
|
0629b1e2d2 | ||
|
|
0d9cf63dd2 | ||
|
|
6513bd5fe0 | ||
|
|
f933e3de3f | ||
|
|
88a8d84153 | ||
|
|
8e4f5da791 | ||
|
|
a61d21e501 | ||
|
|
2bcf33661a | ||
|
|
f6df7a06f2 | ||
|
|
de92a2fc0c | ||
|
|
6012f1d592 | ||
|
|
caf676dc33 | ||
|
|
e3ae1bec75 | ||
|
|
b98b517e35 | ||
|
|
5d9f25eef5 | ||
|
|
5bf69eb539 | ||
|
|
09f7778294 | ||
|
|
c8ec5f3579 | ||
|
|
a54c7ecc18 | ||
|
|
0064caf1f4 | ||
|
|
fc2fbd4689 | ||
|
|
0f0793cde5 | ||
|
|
2fed6f61e9 | ||
|
|
3df310df6e | ||
|
|
c2b3a749ca | ||
|
|
2d2220f38f | ||
|
|
7509bf85aa | ||
|
|
64e8088ae4 | ||
|
|
15584b9b34 | ||
|
|
79c1d1b0a6 | ||
|
|
50860614cf | ||
|
|
90d1d3e053 | ||
|
|
3bf83b52fb | ||
|
|
5f57dd7a62 | ||
|
|
8e1185b56f | ||
|
|
26098df2a1 | ||
|
|
9ac9d83745 | ||
|
|
51edd5a3f4 | ||
|
|
fc07f90f91 | ||
|
|
b64dcbf502 | ||
|
|
5694c113be | ||
|
|
01cf5c21a7 | ||
|
|
4206d2e131 | ||
|
|
83968553aa | ||
|
|
aa2aba1250 | ||
|
|
bba9c4b976 | ||
|
|
999eef2ec9 | ||
|
|
f28c8903aa | ||
|
|
f58eabe667 | ||
|
|
86695dfe29 | ||
|
|
9ae452e8d6 | ||
|
|
3e547102d2 | ||
|
|
e883e63c87 | ||
|
|
a904047a16 | ||
|
|
ad1af792e6 | ||
|
|
6c9527d9dc | ||
|
|
da2d461aa8 | ||
|
|
49bfd69707 | ||
|
|
2a02df9411 | ||
|
|
185ba80e99 | ||
|
|
127cbf3f96 | ||
|
|
4bdf675def | ||
|
|
9c944924de | ||
|
|
28f79533eb | ||
|
|
5a834c9500 | ||
|
|
3255218d5c | ||
|
|
9befe377d5 | ||
|
|
f39b4f0750 | ||
|
|
1794625cea | ||
|
|
42092fe6dd |
26
Makefile
26
Makefile
@@ -1,7 +1,7 @@
|
||||
CSC = gmcs
|
||||
CSFLAGS = -nologo -warn:4 -debug:+ -debug:full -optimize- -codepage:utf8 -unsafe
|
||||
DEFINE = DEBUG;TRACE
|
||||
PROGRAMS =fileformats gl game ra cnc seqed editor ralint filex tsbuild
|
||||
PROGRAMS =fileformats gl game ra cnc seqed editor ralint filex tsbuild utility
|
||||
prefix = /usr/local
|
||||
datarootdir = $(prefix)/share
|
||||
datadir = $(datarootdir)
|
||||
@@ -16,7 +16,7 @@ COMMON_LIBS = System.dll System.Core.dll System.Drawing.dll System.Xml.dll
|
||||
fileformats_SRCS = $(shell find OpenRA.FileFormats/ -iname '*.cs')
|
||||
fileformats_TARGET = OpenRA.FileFormats.dll
|
||||
fileformats_KIND = library
|
||||
fileformats_LIBS = $(COMMON_LIBS) thirdparty/Tao/Tao.Sdl.dll thirdparty/WindowsBase.dll
|
||||
fileformats_LIBS = $(COMMON_LIBS) thirdparty/Tao/Tao.Sdl.dll System.Windows.Forms.dll thirdparty/WindowsBase.dll
|
||||
|
||||
gl_SRCS = $(shell find OpenRA.Gl/ -iname '*.cs')
|
||||
gl_TARGET = OpenRA.Gl.dll
|
||||
@@ -62,13 +62,13 @@ editor_EXTRA = -resource:OpenRA.Editor.Form1.resources -resource:OpenRA.Editor.
|
||||
|
||||
ralint_SRCS = $(shell find RALint/ -iname '*.cs')
|
||||
ralint_TARGET = RALint.exe
|
||||
ralint_KIND = winexe
|
||||
ralint_KIND = exe
|
||||
ralint_DEPS = $(fileformats_TARGET) $(game_TARGET)
|
||||
ralint_LIBS = $(COMMON_LIBS) $(ralint_DEPS)
|
||||
|
||||
filex_SRCS = $(shell find FileExtractor/ -iname '*.cs')
|
||||
filex_TARGET = FileExtractor.exe
|
||||
filex_KIND = winexe
|
||||
filex_KIND = exe
|
||||
filex_DEPS = $(fileformats_TARGET)
|
||||
filex_LIBS = $(COMMON_LIBS) $(filex_DEPS)
|
||||
|
||||
@@ -79,19 +79,26 @@ tsbuild_DEPS = $(fileformats_TARGET) $(game_TARGET)
|
||||
tsbuild_LIBS = $(COMMON_LIBS) $(tsbuild_DEPS) System.Windows.Forms.dll
|
||||
tsbuild_EXTRA = -resource:OpenRA.TilesetBuilder.Form1.resources
|
||||
|
||||
utility_SRCS = $(shell find OpenRA.Utility/ -iname '*.cs')
|
||||
utility_TARGET = OpenRA.Utility.exe
|
||||
utility_KIND = exe
|
||||
utility_DEPS = $(fileformats_TARGET) thirdparty/ICSharpCode.SharpZipLib.dll
|
||||
utility_LIBS = $(COMMON_LIBS) $(utility_DEPS)
|
||||
|
||||
|
||||
# -platform:x86
|
||||
|
||||
.SUFFIXES:
|
||||
.PHONY: clean all game tool default mods mod_ra mod_cnc install uninstall editor_res editor tsbuild ralint seqed filex
|
||||
.PHONY: clean all game tool default mods mod_ra mod_cnc install uninstall editor_res editor tsbuild ralint seqed filex utility
|
||||
|
||||
game: $(fileformats_TARGET) $(gl_TARGET) $(game_TARGET) $(ra_TARGET) $(cnc_TARGET)
|
||||
game: $(fileformats_TARGET) $(gl_TARGET) $(game_TARGET) $(ra_TARGET) $(cnc_TARGET) $(utility_TARGET)
|
||||
|
||||
clean:
|
||||
@-rm *.exe *.dll *.mdb mods/**/*.dll mods/**/*.mdb *.resources
|
||||
|
||||
distclean: clean
|
||||
|
||||
CORE = fileformats gl game editor
|
||||
CORE = fileformats gl game editor utility
|
||||
|
||||
install: all
|
||||
@-echo "Installing OpenRA to $(INSTALL_DIR)"
|
||||
@@ -123,6 +130,7 @@ install: all
|
||||
@cp *.ttf $(INSTALL_DIR)
|
||||
@cp --parents -r thirdparty/Tao $(INSTALL_DIR)
|
||||
@$(INSTALL_PROGRAM) thirdparty/WindowsBase.dll $(INSTALL_DIR)
|
||||
@$(INSTALL_PROGRAM) thirdparty/ICSharpCode.SharpZipLib.dll $(INSTALL_DIR)
|
||||
@-$(INSTALL_PROGRAM) VERSION $(INSTALL_DIR)
|
||||
|
||||
@echo "#!/bin/sh" > openra
|
||||
@@ -132,8 +140,8 @@ install: all
|
||||
@$(INSTALL_PROGRAM) -m +rx openra $(BIN_INSTALL_DIR)
|
||||
|
||||
@echo "OpenRA is now installed. You will now want to download"
|
||||
@echo "http://open-ra.org/get-dependency.php?ra-packages and"
|
||||
@echo "http://open-ra.org/get-dependency.php?cnc-packages"
|
||||
@echo "http://open-ra.org/get-dependency.php?file=ra-packages and"
|
||||
@echo "http://open-ra.org/get-dependency.php?file=cnc-packages"
|
||||
@echo "and extract their contents to"
|
||||
@echo "$(INSTALL_DIR)/mods/ra/packages and "
|
||||
@echo "$(INSTALL_DIR)/mods/cnc/packages respectively."
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace OpenRA.Editor
|
||||
{
|
||||
public Bitmap Bitmap;
|
||||
public ActorInfo Info;
|
||||
public bool Centered;
|
||||
public EditorAppearanceInfo Appearance;
|
||||
}
|
||||
|
||||
class BrushTemplate
|
||||
|
||||
53
OpenRA.Editor/Form1.Designer.cs
generated
Normal file → Executable file
53
OpenRA.Editor/Form1.Designer.cs
generated
Normal file → Executable file
@@ -65,6 +65,9 @@
|
||||
this.tt = new System.Windows.Forms.ToolTip(this.components);
|
||||
this.saveFileDialog = new System.Windows.Forms.SaveFileDialog();
|
||||
this.splitContainer3 = new System.Windows.Forms.SplitContainer();
|
||||
this.statusStrip1 = new System.Windows.Forms.StatusStrip();
|
||||
this.toolStripStatusLabelFiller = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.toolStripStatusLabelMousePosition = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.surface1 = new OpenRA.Editor.Surface();
|
||||
this.splitContainer1.Panel1.SuspendLayout();
|
||||
this.splitContainer1.Panel2.SuspendLayout();
|
||||
@@ -81,6 +84,7 @@
|
||||
this.splitContainer3.Panel1.SuspendLayout();
|
||||
this.splitContainer3.Panel2.SuspendLayout();
|
||||
this.splitContainer3.SuspendLayout();
|
||||
this.statusStrip1.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// splitContainer1
|
||||
@@ -115,7 +119,7 @@
|
||||
//
|
||||
this.splitContainer2.Panel2.Controls.Add(this.tabControl1);
|
||||
this.splitContainer2.Size = new System.Drawing.Size(198, 744);
|
||||
this.splitContainer2.SplitterDistance = 182;
|
||||
this.splitContainer2.SplitterDistance = 164;
|
||||
this.splitContainer2.TabIndex = 1;
|
||||
//
|
||||
// pmMiniMap
|
||||
@@ -125,7 +129,7 @@
|
||||
this.pmMiniMap.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.pmMiniMap.Location = new System.Drawing.Point(0, 0);
|
||||
this.pmMiniMap.Name = "pmMiniMap";
|
||||
this.pmMiniMap.Size = new System.Drawing.Size(198, 182);
|
||||
this.pmMiniMap.Size = new System.Drawing.Size(198, 164);
|
||||
this.pmMiniMap.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
|
||||
this.pmMiniMap.TabIndex = 1;
|
||||
this.pmMiniMap.TabStop = false;
|
||||
@@ -142,7 +146,7 @@
|
||||
this.tabControl1.Name = "tabControl1";
|
||||
this.tabControl1.Padding = new System.Drawing.Point(6, 0);
|
||||
this.tabControl1.SelectedIndex = 0;
|
||||
this.tabControl1.Size = new System.Drawing.Size(198, 558);
|
||||
this.tabControl1.Size = new System.Drawing.Size(198, 576);
|
||||
this.tabControl1.TabIndex = 0;
|
||||
//
|
||||
// tabPage1
|
||||
@@ -151,7 +155,7 @@
|
||||
this.tabPage1.Location = new System.Drawing.Point(4, 20);
|
||||
this.tabPage1.Name = "tabPage1";
|
||||
this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.tabPage1.Size = new System.Drawing.Size(190, 534);
|
||||
this.tabPage1.Size = new System.Drawing.Size(190, 552);
|
||||
this.tabPage1.TabIndex = 0;
|
||||
this.tabPage1.Text = "Templates";
|
||||
this.tabPage1.UseVisualStyleBackColor = true;
|
||||
@@ -163,7 +167,7 @@
|
||||
this.tilePalette.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tilePalette.Location = new System.Drawing.Point(3, 3);
|
||||
this.tilePalette.Name = "tilePalette";
|
||||
this.tilePalette.Size = new System.Drawing.Size(184, 528);
|
||||
this.tilePalette.Size = new System.Drawing.Size(184, 546);
|
||||
this.tilePalette.TabIndex = 1;
|
||||
//
|
||||
// tabPage2
|
||||
@@ -172,7 +176,7 @@
|
||||
this.tabPage2.Location = new System.Drawing.Point(4, 20);
|
||||
this.tabPage2.Name = "tabPage2";
|
||||
this.tabPage2.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.tabPage2.Size = new System.Drawing.Size(190, 534);
|
||||
this.tabPage2.Size = new System.Drawing.Size(190, 552);
|
||||
this.tabPage2.TabIndex = 1;
|
||||
this.tabPage2.Text = "Actors";
|
||||
this.tabPage2.UseVisualStyleBackColor = true;
|
||||
@@ -184,7 +188,7 @@
|
||||
this.actorPalette.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.actorPalette.Location = new System.Drawing.Point(3, 3);
|
||||
this.actorPalette.Name = "actorPalette";
|
||||
this.actorPalette.Size = new System.Drawing.Size(184, 528);
|
||||
this.actorPalette.Size = new System.Drawing.Size(184, 546);
|
||||
this.actorPalette.TabIndex = 2;
|
||||
//
|
||||
// tabPage3
|
||||
@@ -192,7 +196,7 @@
|
||||
this.tabPage3.Controls.Add(this.resourcePalette);
|
||||
this.tabPage3.Location = new System.Drawing.Point(4, 20);
|
||||
this.tabPage3.Name = "tabPage3";
|
||||
this.tabPage3.Size = new System.Drawing.Size(190, 534);
|
||||
this.tabPage3.Size = new System.Drawing.Size(190, 552);
|
||||
this.tabPage3.TabIndex = 2;
|
||||
this.tabPage3.Text = "Resources";
|
||||
this.tabPage3.UseVisualStyleBackColor = true;
|
||||
@@ -204,7 +208,7 @@
|
||||
this.resourcePalette.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.resourcePalette.Location = new System.Drawing.Point(0, 0);
|
||||
this.resourcePalette.Name = "resourcePalette";
|
||||
this.resourcePalette.Size = new System.Drawing.Size(190, 534);
|
||||
this.resourcePalette.Size = new System.Drawing.Size(190, 552);
|
||||
this.resourcePalette.TabIndex = 3;
|
||||
//
|
||||
// menuStrip1
|
||||
@@ -417,6 +421,30 @@
|
||||
this.splitContainer3.SplitterDistance = 25;
|
||||
this.splitContainer3.TabIndex = 6;
|
||||
//
|
||||
// statusStrip1
|
||||
//
|
||||
this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.toolStripStatusLabelFiller,
|
||||
this.toolStripStatusLabelMousePosition});
|
||||
this.statusStrip1.Location = new System.Drawing.Point(0, 751);
|
||||
this.statusStrip1.Name = "statusStrip1";
|
||||
this.statusStrip1.Size = new System.Drawing.Size(985, 22);
|
||||
this.statusStrip1.TabIndex = 7;
|
||||
this.statusStrip1.Text = "statusStrip1";
|
||||
//
|
||||
// toolStripStatusLabelFiller
|
||||
//
|
||||
this.toolStripStatusLabelFiller.Name = "toolStripStatusLabelFiller";
|
||||
this.toolStripStatusLabelFiller.Size = new System.Drawing.Size(948, 17);
|
||||
this.toolStripStatusLabelFiller.Spring = true;
|
||||
//
|
||||
// toolStripStatusLabelMousePosition
|
||||
//
|
||||
this.toolStripStatusLabelMousePosition.Name = "toolStripStatusLabelMousePosition";
|
||||
this.toolStripStatusLabelMousePosition.RightToLeft = System.Windows.Forms.RightToLeft.Yes;
|
||||
this.toolStripStatusLabelMousePosition.Size = new System.Drawing.Size(22, 17);
|
||||
this.toolStripStatusLabelMousePosition.Text = "0,0";
|
||||
//
|
||||
// surface1
|
||||
//
|
||||
this.surface1.BackColor = System.Drawing.Color.Black;
|
||||
@@ -432,6 +460,7 @@
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(985, 773);
|
||||
this.Controls.Add(this.statusStrip1);
|
||||
this.Controls.Add(this.splitContainer3);
|
||||
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||
this.KeyPreview = true;
|
||||
@@ -459,7 +488,10 @@
|
||||
this.splitContainer3.Panel1.PerformLayout();
|
||||
this.splitContainer3.Panel2.ResumeLayout(false);
|
||||
this.splitContainer3.ResumeLayout(false);
|
||||
this.statusStrip1.ResumeLayout(false);
|
||||
this.statusStrip1.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
@@ -501,6 +533,9 @@
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuMinimapToPNG;
|
||||
private System.Windows.Forms.SaveFileDialog saveFileDialog;
|
||||
private System.Windows.Forms.SplitContainer splitContainer3;
|
||||
private System.Windows.Forms.StatusStrip statusStrip1;
|
||||
private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabelMousePosition;
|
||||
private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabelFiller;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
5
OpenRA.Editor/Form1.cs
Normal file → Executable file
5
OpenRA.Editor/Form1.cs
Normal file → Executable file
@@ -36,6 +36,7 @@ namespace OpenRA.Editor
|
||||
Rules.LoadRules(Game.modData.Manifest, new Map());
|
||||
|
||||
surface1.AfterChange += OnMapChanged;
|
||||
surface1.MousePositionChanged += s => toolStripStatusLabelMousePosition.Text = s;
|
||||
}
|
||||
|
||||
void OnMapChanged()
|
||||
@@ -61,7 +62,7 @@ namespace OpenRA.Editor
|
||||
Game.modData = new ModData(currentMod);
|
||||
|
||||
// load the map
|
||||
var map = new Map(new Folder(mapname));
|
||||
var map = new Map(new Folder(mapname, 0));
|
||||
|
||||
// upgrade maps that have no player definitions. editor doesnt care,
|
||||
// but this breaks the game pretty badly.
|
||||
@@ -240,7 +241,6 @@ namespace OpenRA.Editor
|
||||
else
|
||||
{
|
||||
surface1.Map.PlayerCount = surface1.Map.Waypoints.Count;
|
||||
surface1.Map.Package = new Folder(loadedMapName);
|
||||
surface1.Map.Save(loadedMapName);
|
||||
dirty = false;
|
||||
}
|
||||
@@ -364,7 +364,6 @@ namespace OpenRA.Editor
|
||||
Directory.CreateDirectory(savePath);
|
||||
|
||||
var map = LegacyMapImporter.Import(ofd.FileName);
|
||||
map.Package = new Folder(savePath);
|
||||
map.Players.Add("Neutral", new PlayerReference("Neutral",
|
||||
Rules.Info["world"].Traits.WithInterface<CountryInfo>().First().Race, true, true));
|
||||
|
||||
|
||||
3
OpenRA.Editor/Form1.resx
Normal file → Executable file
3
OpenRA.Editor/Form1.resx
Normal file → Executable file
@@ -311,6 +311,9 @@
|
||||
<metadata name="saveFileDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>76, 17</value>
|
||||
</metadata>
|
||||
<metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>313, 17</value>
|
||||
</metadata>
|
||||
<metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>45</value>
|
||||
</metadata>
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace OpenRA.Editor
|
||||
if (MapList.SelectedItems.Count == 1)
|
||||
{
|
||||
txtNew.Text = MapList.SelectedItems[0].Text;
|
||||
var map = new Map(new Folder(Path.Combine(MapFolderPath, MapList.SelectedItems[0].Text)));
|
||||
var map = new Map(new Folder(Path.Combine(MapFolderPath, MapList.SelectedItems[0].Text), 0));
|
||||
txtTitle.Text = map.Title;
|
||||
txtAuthor.Text = map.Author;
|
||||
txtTheater.Text = map.Theater;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using OpenRA.FileFormats;
|
||||
@@ -17,19 +18,34 @@ namespace OpenRA.Editor
|
||||
{
|
||||
static class RenderUtils
|
||||
{
|
||||
public static ColorPalette MakeSystemPalette(Palette p)
|
||||
{
|
||||
ColorPalette pal;
|
||||
using (var b = new Bitmap(1, 1, PixelFormat.Format8bppIndexed))
|
||||
pal = b.Palette;
|
||||
|
||||
for (var i = 0; i < 256; i++)
|
||||
pal.Entries[i] = p.GetColor(i);
|
||||
return pal;
|
||||
}
|
||||
|
||||
public static Bitmap RenderTemplate(TileSet ts, ushort n, Palette p)
|
||||
{
|
||||
var template = ts.Templates[n];
|
||||
var tile = ts.Tiles[n];
|
||||
|
||||
var bitmap = new Bitmap(ts.TileSize * template.Size.X, ts.TileSize * template.Size.Y);
|
||||
var bitmap = new Bitmap(ts.TileSize * template.Size.X, ts.TileSize * template.Size.Y,
|
||||
PixelFormat.Format8bppIndexed);
|
||||
|
||||
bitmap.Palette = MakeSystemPalette(p);
|
||||
|
||||
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
|
||||
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
|
||||
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
|
||||
|
||||
unsafe
|
||||
{
|
||||
int* q = (int*)data.Scan0.ToPointer();
|
||||
var stride = data.Stride >> 2;
|
||||
byte* q = (byte*)data.Scan0.ToPointer();
|
||||
var stride = data.Stride;
|
||||
|
||||
for (var u = 0; u < template.Size.X; u++)
|
||||
for (var v = 0; v < template.Size.Y; v++)
|
||||
@@ -38,13 +54,13 @@ namespace OpenRA.Editor
|
||||
var rawImage = tile.TileBitmapBytes[u + v * template.Size.X];
|
||||
for (var i = 0; i < ts.TileSize; i++)
|
||||
for (var j = 0; j < ts.TileSize; j++)
|
||||
q[(v * ts.TileSize + j) * stride + u * ts.TileSize + i] = p.GetColor(rawImage[i + ts.TileSize * j]).ToArgb();
|
||||
q[(v * ts.TileSize + j) * stride + u * ts.TileSize + i] = rawImage[i + ts.TileSize * j];
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var i = 0; i < ts.TileSize; i++)
|
||||
for (var j = 0; j < ts.TileSize; j++)
|
||||
q[(v * ts.TileSize + j) * stride + u * ts.TileSize + i] = Color.Transparent.ToArgb();
|
||||
q[(v * ts.TileSize + j) * stride + u * ts.TileSize + i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,18 +72,21 @@ namespace OpenRA.Editor
|
||||
{
|
||||
var frame = shp[0];
|
||||
|
||||
var bitmap = new Bitmap(shp.Width, shp.Height);
|
||||
var bitmap = new Bitmap(shp.Width, shp.Height, PixelFormat.Format8bppIndexed);
|
||||
|
||||
bitmap.Palette = MakeSystemPalette(p);
|
||||
|
||||
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
|
||||
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
|
||||
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
|
||||
|
||||
unsafe
|
||||
{
|
||||
int* q = (int*)data.Scan0.ToPointer();
|
||||
var stride2 = data.Stride >> 2;
|
||||
byte* q = (byte*)data.Scan0.ToPointer();
|
||||
var stride2 = data.Stride;
|
||||
|
||||
for (var i = 0; i < shp.Width; i++)
|
||||
for (var j = 0; j < shp.Height; j++)
|
||||
q[j * stride2 + i] = p.GetColor(frame.Image[i + shp.Width * j]).ToArgb();
|
||||
q[j * stride2 + i] = frame.Image[i + shp.Width * j];
|
||||
}
|
||||
|
||||
bitmap.UnlockBits(data);
|
||||
@@ -102,7 +121,12 @@ namespace OpenRA.Editor
|
||||
}
|
||||
catch { }
|
||||
|
||||
return new ActorTemplate { Bitmap = bitmap, Info = info, Centered = !info.Traits.Contains<BuildingInfo>() };
|
||||
return new ActorTemplate
|
||||
{
|
||||
Bitmap = bitmap,
|
||||
Info = info,
|
||||
Appearance = info.Traits.GetOrDefault<EditorAppearanceInfo>()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,18 +138,19 @@ namespace OpenRA.Editor
|
||||
var shp = new ShpReader(s);
|
||||
var frame = shp[shp.ImageCount - 1];
|
||||
|
||||
var bitmap = new Bitmap(shp.Width, shp.Height);
|
||||
var bitmap = new Bitmap(shp.Width, shp.Height, PixelFormat.Format8bppIndexed);
|
||||
bitmap.Palette = MakeSystemPalette(p);
|
||||
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
|
||||
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
|
||||
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
|
||||
|
||||
unsafe
|
||||
{
|
||||
int* q = (int*)data.Scan0.ToPointer();
|
||||
var stride = data.Stride >> 2;
|
||||
byte* q = (byte*)data.Scan0.ToPointer();
|
||||
var stride = data.Stride;
|
||||
|
||||
for (var i = 0; i < shp.Width; i++)
|
||||
for (var j = 0; j < shp.Height; j++)
|
||||
q[j * stride + i] = p.GetColor(frame.Image[i + shp.Width * j]).ToArgb();
|
||||
q[j * stride + i] = frame.Image[i + shp.Width * j];
|
||||
}
|
||||
|
||||
bitmap.UnlockBits(data);
|
||||
|
||||
@@ -15,6 +15,7 @@ using System.Drawing.Imaging;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Editor
|
||||
{
|
||||
@@ -34,6 +35,7 @@ namespace OpenRA.Editor
|
||||
|
||||
public bool IsPanning;
|
||||
public event Action AfterChange = () => { };
|
||||
public event Action<string> MousePositionChanged = _ => { };
|
||||
|
||||
Dictionary<string, ActorTemplate> ActorTemplates = new Dictionary<string, ActorTemplate>();
|
||||
Dictionary<int, ResourceTemplate> ResourceTemplates = new Dictionary<int, ResourceTemplate>();
|
||||
@@ -44,6 +46,7 @@ namespace OpenRA.Editor
|
||||
TileSet = ts;
|
||||
Palette = p;
|
||||
Brush = null;
|
||||
PlayerPalettes = null;
|
||||
Chunks.Clear();
|
||||
}
|
||||
|
||||
@@ -120,6 +123,7 @@ namespace OpenRA.Editor
|
||||
|
||||
var oldMousePos = MousePos;
|
||||
MousePos = new int2(e.Location);
|
||||
MousePositionChanged(GetBrushLocation().ToString());
|
||||
|
||||
if (e.Button == MouseButtons.Middle || (e.Button != MouseButtons.None && IsPanning))
|
||||
Scroll(oldMousePos - MousePos);
|
||||
@@ -171,7 +175,7 @@ namespace OpenRA.Editor
|
||||
{
|
||||
for (; ; )
|
||||
{
|
||||
var q = p+d;
|
||||
var q = p + d;
|
||||
if (!Map.IsInMap(q)) return p;
|
||||
if (!Map.MapTiles[q.X, q.Y].Equals(replace)) return p;
|
||||
p = q;
|
||||
@@ -203,7 +207,7 @@ namespace OpenRA.Editor
|
||||
{
|
||||
type = Brush.N,
|
||||
index = template.PickAny ? byte.MaxValue : (byte)z,
|
||||
image = template.PickAny ? (byte)((u + pos.X) % 4 + ((v + pos.Y) % 4)*4) : (byte)z,
|
||||
image = template.PickAny ? (byte)((u + pos.X) % 4 + ((v + pos.Y) % 4) * 4) : (byte)z,
|
||||
};
|
||||
|
||||
var ch = new int2((pos.X + u) / ChunkSize, (pos.Y + v) / ChunkSize);
|
||||
@@ -407,19 +411,25 @@ namespace OpenRA.Editor
|
||||
return new int2(vX / TileSet.TileSize, vY / TileSet.TileSize);
|
||||
}
|
||||
|
||||
void DrawActor(System.Drawing.Graphics g, int2 p, ActorTemplate t)
|
||||
void DrawActor(System.Drawing.Graphics g, int2 p, ActorTemplate t, ColorPalette cp)
|
||||
{
|
||||
float OffsetX = t.Centered ? t.Bitmap.Width / 2 - TileSet.TileSize/2 : 0;
|
||||
var centered = t.Appearance == null || !t.Appearance.RelativeToTopLeft;
|
||||
|
||||
float OffsetX = centered ? t.Bitmap.Width / 2 - TileSet.TileSize / 2 : 0;
|
||||
float DrawX = TileSet.TileSize * p.X * Zoom + Offset.X - OffsetX;
|
||||
|
||||
float OffsetY = t.Centered ? t.Bitmap.Height / 2 - TileSet.TileSize/2 : 0;
|
||||
float OffsetY = centered ? t.Bitmap.Height / 2 - TileSet.TileSize / 2 : 0;
|
||||
float DrawY = TileSet.TileSize * p.Y * Zoom + Offset.Y - OffsetY;
|
||||
|
||||
float width = t.Bitmap.Width * Zoom;
|
||||
float height = t.Bitmap.Height * Zoom;
|
||||
RectangleF sourceRect = new RectangleF(0, 0, t.Bitmap.Width, t.Bitmap.Height);
|
||||
RectangleF destRect = new RectangleF(DrawX, DrawY, width, height);
|
||||
|
||||
var restorePalette = t.Bitmap.Palette;
|
||||
if (cp != null) t.Bitmap.Palette = cp;
|
||||
g.DrawImage(t.Bitmap, destRect, sourceRect, GraphicsUnit.Pixel);
|
||||
if (cp != null) t.Bitmap.Palette = restorePalette;
|
||||
}
|
||||
|
||||
void DrawImage(System.Drawing.Graphics g, Bitmap bmp, int2 location)
|
||||
@@ -439,10 +449,12 @@ namespace OpenRA.Editor
|
||||
|
||||
void DrawActorBorder(System.Drawing.Graphics g, int2 p, ActorTemplate t)
|
||||
{
|
||||
float OffsetX = t.Centered ? t.Bitmap.Width / 2 - TileSet.TileSize / 2 : 0;
|
||||
var centered = t.Appearance == null || !t.Appearance.RelativeToTopLeft;
|
||||
|
||||
float OffsetX = centered ? t.Bitmap.Width / 2 - TileSet.TileSize / 2 : 0;
|
||||
float DrawX = TileSet.TileSize * p.X * Zoom + Offset.X - OffsetX;
|
||||
|
||||
float OffsetY = t.Centered ? t.Bitmap.Height / 2 - TileSet.TileSize / 2 : 0;
|
||||
float OffsetY = centered ? t.Bitmap.Height / 2 - TileSet.TileSize / 2 : 0;
|
||||
float DrawY = TileSet.TileSize * p.Y * Zoom + Offset.Y - OffsetY;
|
||||
|
||||
g.DrawRectangle(CordonPen,
|
||||
@@ -450,20 +462,42 @@ namespace OpenRA.Editor
|
||||
t.Bitmap.Width * Zoom, t.Bitmap.Height * Zoom);
|
||||
}
|
||||
|
||||
ColorPalette GetPaletteForPlayer(string name)
|
||||
{
|
||||
var pr = Map.Players[name];
|
||||
var pcpi = Rules.Info["player"].Traits.Get<PlayerColorPaletteInfo>();
|
||||
var remap = new PlayerColorRemap(pr.Color, pr.Color2, pcpi.PaletteFormat);
|
||||
return RenderUtils.MakeSystemPalette(new Palette(Palette, remap));
|
||||
}
|
||||
|
||||
Cache<string, ColorPalette> PlayerPalettes;
|
||||
|
||||
ColorPalette GetPaletteForActor(ActorReference ar)
|
||||
{
|
||||
if (PlayerPalettes == null)
|
||||
PlayerPalettes = new Cache<string, ColorPalette>(GetPaletteForPlayer);
|
||||
|
||||
var ownerInit = ar.InitDict.GetOrDefault<OwnerInit>();
|
||||
if (ownerInit == null)
|
||||
return null;
|
||||
|
||||
return PlayerPalettes[ownerInit.PlayerName];
|
||||
}
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
if (Map == null) return;
|
||||
if (TileSet == null) return;
|
||||
|
||||
for( var u = 0; u < Map.MapSize.X; u += ChunkSize )
|
||||
for (var u = 0; u < Map.MapSize.X; u += ChunkSize)
|
||||
for (var v = 0; v < Map.MapSize.Y; v += ChunkSize)
|
||||
{
|
||||
var x = new int2(u/ChunkSize,v/ChunkSize);
|
||||
var x = new int2(u / ChunkSize, v / ChunkSize);
|
||||
if (!Chunks.ContainsKey(x)) Chunks[x] = RenderChunk(u / ChunkSize, v / ChunkSize);
|
||||
|
||||
Bitmap bmp = Chunks[x];
|
||||
|
||||
float DrawX = TileSet.TileSize* 1f * (float)ChunkSize * (float)x.X * Zoom + Offset.X;
|
||||
float DrawX = TileSet.TileSize * 1f * (float)ChunkSize * (float)x.X * Zoom + Offset.X;
|
||||
float DrawY = TileSet.TileSize * 1f * (float)ChunkSize * (float)x.Y * Zoom + Offset.Y;
|
||||
RectangleF sourceRect = new RectangleF(0, 0, bmp.Width, bmp.Height);
|
||||
RectangleF destRect = new RectangleF(DrawX, DrawY, bmp.Width * Zoom, bmp.Height * Zoom);
|
||||
@@ -477,7 +511,8 @@ namespace OpenRA.Editor
|
||||
Map.Height * TileSet.TileSize * Zoom);
|
||||
|
||||
foreach (var ar in Map.Actors)
|
||||
DrawActor(e.Graphics, ar.Value.Location(), ActorTemplates[ar.Value.Type]);
|
||||
DrawActor(e.Graphics, ar.Value.Location(), ActorTemplates[ar.Value.Type],
|
||||
GetPaletteForActor(ar.Value));
|
||||
|
||||
foreach (var wp in Map.Waypoints)
|
||||
e.Graphics.DrawRectangle(Pens.LimeGreen,
|
||||
@@ -493,7 +528,8 @@ namespace OpenRA.Editor
|
||||
Brush.Bitmap.Height * Zoom);
|
||||
|
||||
if (Actor != null)
|
||||
DrawActor(e.Graphics, GetBrushLocation(), Actor);
|
||||
DrawActor(e.Graphics, GetBrushLocation(), Actor, null); /* todo: include the player
|
||||
* in the brush so we can color new buildings too */
|
||||
|
||||
if (Resource != null)
|
||||
DrawImage(e.Graphics, Resource.Bitmap, GetBrushLocation());
|
||||
|
||||
@@ -105,6 +105,14 @@ namespace OpenRA.FileFormats
|
||||
return InvalidValueAction(x,fieldType, field);
|
||||
}
|
||||
|
||||
else if (fieldType == typeof(decimal))
|
||||
{
|
||||
decimal res;
|
||||
if (decimal.TryParse(x.Replace("%",""), System.Globalization.NumberStyles.Any, NumberFormatInfo.InvariantInfo, out res))
|
||||
return res * (x.Contains( '%' ) ? 0.01m : 1m);
|
||||
return InvalidValueAction(x,fieldType, field);
|
||||
}
|
||||
|
||||
else if (fieldType == typeof(string))
|
||||
return x;
|
||||
|
||||
|
||||
274
OpenRA.FileFormats/FileFormats/Blast.cs
Normal file
274
OpenRA.FileFormats/FileFormats/Blast.cs
Normal file
@@ -0,0 +1,274 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*
|
||||
* This file is based on the blast routines (version 1.1 by Mark Adler)
|
||||
* included in zlib/contrib
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
public static class Blast
|
||||
{
|
||||
public static readonly int MAXBITS = 13; // maximum code length
|
||||
public static readonly int MAXWIN = 4096; // maximum window size
|
||||
|
||||
static byte[] litlen = new byte[] {
|
||||
11, 124, 8, 7, 28, 7, 188, 13, 76, 4,
|
||||
10, 8, 12, 10, 12, 10, 8, 23, 8, 9,
|
||||
7, 6, 7, 8, 7, 6, 55, 8, 23, 24,
|
||||
12, 11, 7, 9, 11, 12, 6, 7, 22, 5,
|
||||
7, 24, 6, 11, 9, 6, 7, 22, 7, 11,
|
||||
38, 7, 9, 8, 25, 11, 8, 11, 9, 12,
|
||||
8, 12, 5, 38, 5, 38, 5, 11, 7, 5,
|
||||
6, 21, 6, 10, 53, 8, 7, 24, 10, 27,
|
||||
44, 253, 253, 253, 252, 252, 252, 13, 12, 45,
|
||||
12, 45, 12, 61, 12, 45, 44, 173
|
||||
};
|
||||
|
||||
// bit lengths of length codes 0..15
|
||||
static byte[] lenlen = new byte[] { 2, 35, 36, 53, 38, 23 };
|
||||
|
||||
// bit lengths of distance codes 0..63
|
||||
static byte[] distlen = new byte[] { 2, 20, 53, 230, 247, 151, 248 };
|
||||
|
||||
// base for length codes
|
||||
static short[] lengthbase = new short[] {
|
||||
3, 2, 4, 5, 6, 7, 8, 9, 10, 12,
|
||||
16, 24, 40, 72, 136, 264
|
||||
};
|
||||
|
||||
// extra bits for length codes
|
||||
static byte[] extra = new byte[] {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 2,
|
||||
3, 4, 5, 6, 7, 8
|
||||
};
|
||||
|
||||
static Huffman litcode = new Huffman(litlen, litlen.Length, 256);
|
||||
static Huffman lencode = new Huffman(lenlen, lenlen.Length, 16);
|
||||
static Huffman distcode = new Huffman(distlen, distlen.Length, 64);
|
||||
|
||||
// Decode PKWare Compression Library stream.
|
||||
public static byte[] Decompress(byte[] src)
|
||||
{
|
||||
BitReader br = new BitReader(src);
|
||||
|
||||
// Are literals coded?
|
||||
int coded = br.ReadBits(8);
|
||||
|
||||
if (coded < 0 || coded > 1)
|
||||
throw new NotImplementedException("Invalid datastream");
|
||||
bool EncodedLiterals = (coded == 1);
|
||||
|
||||
// log2(dictionary size) - 6
|
||||
int dict = br.ReadBits(8);
|
||||
if (dict < 4 || dict > 6)
|
||||
throw new InvalidDataException("Invalid dictionary size");
|
||||
|
||||
// output state
|
||||
ushort next = 0; // index of next write location in out[]
|
||||
bool first = true; // true to check distances (for first 4K)
|
||||
byte[] outBuffer = new byte[MAXWIN]; // output buffer and sliding window
|
||||
var ms = new MemoryStream();
|
||||
|
||||
// decode literals and length/distance pairs
|
||||
do
|
||||
{
|
||||
// length/distance pair
|
||||
if (br.ReadBits(1) == 1)
|
||||
{
|
||||
// Length
|
||||
int symbol = Decode(lencode, br);
|
||||
int len = lengthbase[symbol] + br.ReadBits(extra[symbol]);
|
||||
if (len == 519) // Magic number for "done"
|
||||
{
|
||||
for (int i = 0; i < next; i++)
|
||||
ms.WriteByte(outBuffer[i]);
|
||||
break;
|
||||
}
|
||||
|
||||
// Distance
|
||||
symbol = len == 2 ? 2 : dict;
|
||||
int dist = Decode(distcode, br) << symbol;
|
||||
dist += br.ReadBits(symbol);
|
||||
dist++;
|
||||
|
||||
if (first && dist > next)
|
||||
throw new InvalidDataException("Attempt to jump before data");
|
||||
|
||||
// copy length bytes from distance bytes back
|
||||
do
|
||||
{
|
||||
int dest = next;
|
||||
int source = dest - dist;
|
||||
|
||||
int copy = MAXWIN;
|
||||
if (next < dist)
|
||||
{
|
||||
source += copy;
|
||||
copy = dist;
|
||||
}
|
||||
|
||||
copy -= next;
|
||||
if (copy > len)
|
||||
copy = len;
|
||||
|
||||
len -= copy;
|
||||
next += (ushort)copy;
|
||||
Array.Copy(outBuffer, source, outBuffer, dest, copy);
|
||||
|
||||
// Flush window to outstream
|
||||
if (next == MAXWIN)
|
||||
{
|
||||
for (int i = 0; i < next; i++)
|
||||
ms.WriteByte(outBuffer[i]);
|
||||
next = 0;
|
||||
first = false;
|
||||
}
|
||||
} while (len != 0);
|
||||
}
|
||||
else // literal value
|
||||
{
|
||||
int symbol = EncodedLiterals ? Decode(litcode, br) : br.ReadBits(8);
|
||||
outBuffer[next++] = (byte)symbol;
|
||||
if (next == MAXWIN)
|
||||
{
|
||||
for (int i = 0; i < next; i++)
|
||||
ms.WriteByte(outBuffer[i]);
|
||||
next = 0;
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
} while (true);
|
||||
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
// Decode a code using huffman table h.
|
||||
private static int Decode(Huffman h, BitReader br)
|
||||
{
|
||||
int code = 0; // len bits being decoded
|
||||
int first = 0; // first code of length len
|
||||
int index = 0; // index of first code of length len in symbol table
|
||||
short next = 1;
|
||||
while (true)
|
||||
{
|
||||
code |= br.ReadBits(1) ^ 1; // invert code
|
||||
int count = h.Count[next++];
|
||||
if (code < first + count)
|
||||
return h.Symbol[index + (code - first)];
|
||||
|
||||
index += count;
|
||||
first += count;
|
||||
first <<= 1;
|
||||
code <<= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BitReader
|
||||
{
|
||||
readonly byte[] src;
|
||||
int offset = 0;
|
||||
int bitBuffer = 0;
|
||||
int bitCount = 0;
|
||||
|
||||
public BitReader(byte[] src)
|
||||
{
|
||||
this.src = src;
|
||||
}
|
||||
|
||||
public int ReadBits(int count)
|
||||
{
|
||||
int ret = 0;
|
||||
int filled = 0;
|
||||
while (filled < count)
|
||||
{
|
||||
if (bitCount == 0)
|
||||
{
|
||||
bitBuffer = src[offset++];
|
||||
bitCount = 8;
|
||||
}
|
||||
|
||||
ret |= (bitBuffer & 1) << filled;
|
||||
bitBuffer >>= 1;
|
||||
bitCount--;
|
||||
filled++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a list of repeated code lengths rep[0..n-1], where each byte is a
|
||||
* count (high four bits + 1) and a code length (low four bits), generate the
|
||||
* list of code lengths. This compaction reduces the size of the object code.
|
||||
* Then given the list of code lengths length[0..n-1] representing a canonical
|
||||
* Huffman code for n symbols, construct the tables required to decode those
|
||||
* codes. Those tables are the number of codes of each length, and the symbols
|
||||
* sorted by length, retaining their original order within each length.
|
||||
*/
|
||||
class Huffman
|
||||
{
|
||||
public short[] Count; // number of symbols of each length
|
||||
public short[] Symbol; // canonically ordered symbols
|
||||
|
||||
public Huffman(byte[] rep, int n, short SymbolCount)
|
||||
{
|
||||
short[] length = new short[256]; // code lengths
|
||||
int s = 0; // current symbol
|
||||
|
||||
// convert compact repeat counts into symbol bit length list
|
||||
foreach (byte code in rep)
|
||||
{
|
||||
int num = (code >> 4) + 1; // Number of codes (top four bits plus 1)
|
||||
byte len = (byte)(code & 15); // Code length (low four bits)
|
||||
do
|
||||
{
|
||||
length[s++] = len;
|
||||
} while (--num > 0);
|
||||
}
|
||||
n = s;
|
||||
|
||||
// count number of codes of each length
|
||||
Count = new short[Blast.MAXBITS + 1];
|
||||
for (int i = 0; i < n; i++)
|
||||
Count[length[i]]++;
|
||||
|
||||
// no codes!
|
||||
if (Count[0] == n)
|
||||
return;
|
||||
|
||||
// check for an over-subscribed or incomplete set of lengths
|
||||
int left = 1; // one possible code of zero length
|
||||
for (int len = 1; len <= Blast.MAXBITS; len++)
|
||||
{
|
||||
left <<= 1;
|
||||
// one more bit, double codes left
|
||||
left -= Count[len];
|
||||
// deduct count from possible codes
|
||||
if (left < 0)
|
||||
throw new InvalidDataException ("over subscribed code set");
|
||||
}
|
||||
|
||||
// generate offsets into symbol table for each length for sorting
|
||||
short[] offs = new short[Blast.MAXBITS + 1];
|
||||
for (int len = 1; len < Blast.MAXBITS; len++)
|
||||
offs[len + 1] = (short)(offs[len] + Count[len]);
|
||||
|
||||
// put symbols in table sorted by length, by symbol order within each length
|
||||
Symbol = new short[SymbolCount];
|
||||
for (short i = 0; i < n; i++)
|
||||
if (length[i] != 0)
|
||||
Symbol[offs[length[i]]++] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,9 +21,11 @@ namespace OpenRA.FileFormats
|
||||
readonly uint[] hashes;
|
||||
readonly Stream s;
|
||||
readonly ZipPackage pkg;
|
||||
int priority;
|
||||
|
||||
public CompressedPackage(string filename)
|
||||
public CompressedPackage(string filename, int priority)
|
||||
{
|
||||
this.priority = priority;
|
||||
s = FileSystem.Open(filename);
|
||||
pkg = (ZipPackage)ZipPackage.Open(s, FileMode.Open);
|
||||
hashes = pkg.GetParts()
|
||||
@@ -41,5 +43,11 @@ namespace OpenRA.FileFormats
|
||||
{
|
||||
return hashes.Contains(PackageEntry.HashFilename(filename));
|
||||
}
|
||||
|
||||
|
||||
public int Priority
|
||||
{
|
||||
get { return 500 + priority; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
@@ -33,14 +34,18 @@ namespace OpenRA.FileFormats
|
||||
}
|
||||
}
|
||||
|
||||
static int order = 0;
|
||||
|
||||
static IFolder OpenPackage(string filename)
|
||||
{
|
||||
if (filename.EndsWith(".mix"))
|
||||
return new Package(filename);
|
||||
return new MixFile(filename, order++);
|
||||
else if (filename.EndsWith(".zip"))
|
||||
return new CompressedPackage(filename);
|
||||
return new CompressedPackage(filename, order++);
|
||||
else if (filename.EndsWith(".Z"))
|
||||
return new InstallShieldPackage(filename, order++);
|
||||
else
|
||||
return new Folder(filename);
|
||||
return new Folder(filename, order++);
|
||||
}
|
||||
|
||||
public static void Mount(string name)
|
||||
@@ -73,9 +78,14 @@ namespace OpenRA.FileFormats
|
||||
|
||||
static Stream GetFromCache( Cache<uint, List<IFolder>> index, string filename )
|
||||
{
|
||||
foreach( var folder in index[ PackageEntry.HashFilename( filename ) ] )
|
||||
if (folder.Exists(filename))
|
||||
return folder.GetContent(filename);
|
||||
var folder = index[PackageEntry.HashFilename(filename)]
|
||||
.Where(x => x.Exists(filename))
|
||||
.OrderBy(x => x.Priority)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (folder != null)
|
||||
return folder.GetContent(filename);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -88,11 +98,13 @@ namespace OpenRA.FileFormats
|
||||
return ret;
|
||||
}
|
||||
|
||||
foreach( IFolder folder in mountedFolders )
|
||||
{
|
||||
if (folder.Exists(filename))
|
||||
return folder.GetContent(filename);
|
||||
}
|
||||
var folder = mountedFolders
|
||||
.Where(x => x.Exists(filename))
|
||||
.OrderByDescending(x => x.Priority)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (folder != null)
|
||||
return folder.GetContent(filename);
|
||||
|
||||
throw new FileNotFoundException( string.Format( "File not found: {0}", filename ), filename );
|
||||
}
|
||||
@@ -17,7 +17,9 @@ namespace OpenRA.FileFormats
|
||||
{
|
||||
readonly string path;
|
||||
|
||||
public Folder(string path) { this.path = path; }
|
||||
int priority;
|
||||
|
||||
public Folder(string path, int priority) { this.path = path; this.priority = priority; }
|
||||
|
||||
public Stream GetContent(string filename)
|
||||
{
|
||||
@@ -28,12 +30,18 @@ namespace OpenRA.FileFormats
|
||||
public IEnumerable<uint> AllFileHashes()
|
||||
{
|
||||
foreach( var filename in Directory.GetFiles( path, "*", SearchOption.TopDirectoryOnly ) )
|
||||
yield return PackageEntry.HashFilename( filename );
|
||||
yield return PackageEntry.HashFilename( Path.GetFileName(filename) );
|
||||
}
|
||||
|
||||
public bool Exists(string filename)
|
||||
{
|
||||
return File.Exists(Path.Combine(path,filename));
|
||||
}
|
||||
|
||||
|
||||
public int Priority
|
||||
{
|
||||
get { return priority; }
|
||||
}
|
||||
}
|
||||
}
|
||||
121
OpenRA.FileFormats/Filesystem/InstallShieldPackage.cs
Normal file
121
OpenRA.FileFormats/Filesystem/InstallShieldPackage.cs
Normal file
@@ -0,0 +1,121 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
public class InstallShieldPackage : IFolder
|
||||
{
|
||||
readonly Dictionary<uint, PackageEntry> index = new Dictionary<uint, PackageEntry>();
|
||||
readonly Stream s;
|
||||
readonly long dataStart = 255;
|
||||
int priority;
|
||||
|
||||
public InstallShieldPackage(string filename, int priority)
|
||||
{
|
||||
this.priority = priority;
|
||||
s = FileSystem.Open(filename);
|
||||
|
||||
// Parse package header
|
||||
BinaryReader reader = new BinaryReader(s);
|
||||
uint signature = reader.ReadUInt32();
|
||||
if (signature != 0x8C655D13)
|
||||
throw new InvalidDataException("Not an Installshield package");
|
||||
|
||||
reader.ReadBytes(8);
|
||||
var FileCount = reader.ReadUInt16();
|
||||
reader.ReadBytes(4);
|
||||
var ArchiveSize = reader.ReadUInt32();
|
||||
reader.ReadBytes(19);
|
||||
var TOCAddress = reader.ReadInt32();
|
||||
reader.ReadBytes(4);
|
||||
var DirCount = reader.ReadUInt16();
|
||||
|
||||
// Parse the directory list
|
||||
s.Seek(TOCAddress, SeekOrigin.Begin);
|
||||
BinaryReader TOCreader = new BinaryReader(s);
|
||||
for (var i = 0; i < DirCount; i++)
|
||||
ParseDirectory(TOCreader);
|
||||
}
|
||||
|
||||
void ParseDirectory(BinaryReader reader)
|
||||
{
|
||||
// Parse directory header
|
||||
var FileCount = reader.ReadUInt16();
|
||||
var ChunkSize = reader.ReadUInt16();
|
||||
var NameLength = reader.ReadUInt16();
|
||||
var DirName = new String(reader.ReadChars(NameLength));
|
||||
|
||||
// Skip to the end of the chunk
|
||||
reader.ReadBytes(ChunkSize - NameLength - 6);
|
||||
|
||||
// Parse files
|
||||
for (var i = 0; i < FileCount; i++)
|
||||
ParseFile(reader);
|
||||
}
|
||||
|
||||
uint AccumulatedData = 0;
|
||||
void ParseFile(BinaryReader reader)
|
||||
{
|
||||
reader.ReadBytes(7);
|
||||
var CompressedSize = reader.ReadUInt32();
|
||||
reader.ReadBytes(12);
|
||||
var ChunkSize = reader.ReadUInt16();
|
||||
reader.ReadBytes(4);
|
||||
var NameLength = reader.ReadByte();
|
||||
var FileName = new String(reader.ReadChars(NameLength));
|
||||
|
||||
var hash = PackageEntry.HashFilename(FileName);
|
||||
index.Add(hash, new PackageEntry(hash,AccumulatedData, CompressedSize));
|
||||
AccumulatedData += CompressedSize;
|
||||
|
||||
// Skip to the end of the chunk
|
||||
reader.ReadBytes(ChunkSize - NameLength - 30);
|
||||
}
|
||||
|
||||
public Stream GetContent(uint hash)
|
||||
{
|
||||
PackageEntry e;
|
||||
if (!index.TryGetValue(hash, out e))
|
||||
return null;
|
||||
|
||||
s.Seek( dataStart + e.Offset, SeekOrigin.Begin );
|
||||
byte[] data = new byte[ e.Length ];
|
||||
s.Read( data, 0, (int)e.Length );
|
||||
|
||||
return new MemoryStream(Blast.Decompress(data));
|
||||
}
|
||||
|
||||
public Stream GetContent(string filename)
|
||||
{
|
||||
return GetContent(PackageEntry.HashFilename(filename));
|
||||
}
|
||||
|
||||
public IEnumerable<uint> AllFileHashes()
|
||||
{
|
||||
return index.Keys;
|
||||
}
|
||||
|
||||
public bool Exists(string filename)
|
||||
{
|
||||
return index.ContainsKey(PackageEntry.HashFilename(filename));
|
||||
}
|
||||
|
||||
|
||||
public int Priority
|
||||
{
|
||||
get { return 2000 + priority; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,17 +20,20 @@ namespace OpenRA.FileFormats
|
||||
Stream GetContent(string filename);
|
||||
bool Exists(string filename);
|
||||
IEnumerable<uint> AllFileHashes();
|
||||
int Priority { get; }
|
||||
}
|
||||
|
||||
public class Package : IFolder
|
||||
public class MixFile : IFolder
|
||||
{
|
||||
readonly Dictionary<uint, PackageEntry> index;
|
||||
readonly bool isRmix, isEncrypted;
|
||||
readonly long dataStart;
|
||||
readonly Stream s;
|
||||
int priority;
|
||||
|
||||
public Package(string filename)
|
||||
public MixFile(string filename, int priority)
|
||||
{
|
||||
this.priority = priority;
|
||||
s = FileSystem.Open(filename);
|
||||
|
||||
BinaryReader reader = new BinaryReader(s);
|
||||
@@ -149,6 +152,12 @@ namespace OpenRA.FileFormats
|
||||
{
|
||||
return index.ContainsKey(PackageEntry.HashFilename(filename));
|
||||
}
|
||||
|
||||
|
||||
public int Priority
|
||||
{
|
||||
get { return 1000 + priority; }
|
||||
}
|
||||
}
|
||||
|
||||
[Flags]
|
||||
@@ -37,10 +37,8 @@ namespace OpenRA.FileFormats.Graphics
|
||||
|
||||
Size WindowSize { get; }
|
||||
|
||||
void Begin();
|
||||
void End();
|
||||
void Clear( Color color );
|
||||
void Present();
|
||||
void Present( IInputHandler inputHandler );
|
||||
|
||||
void DrawIndexedPrimitives( PrimitiveType type, Range<int> vertexRange, Range<int> indexRange );
|
||||
void DrawIndexedPrimitives( PrimitiveType type, int vertexPool, int numPrimitives );
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#region Copyright & License Information
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
@@ -9,16 +9,33 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
public interface IInputHandler
|
||||
{
|
||||
void ModifierKeys( Modifiers mods );
|
||||
void OnKeyInput( KeyInput input );
|
||||
void OnMouseInput( MouseInput input );
|
||||
}
|
||||
|
||||
public struct MouseInput
|
||||
{
|
||||
public MouseInputEvent Event;
|
||||
public int2 Location;
|
||||
public MouseButton Button;
|
||||
public int2 Location;
|
||||
public Modifiers Modifiers;
|
||||
|
||||
public MouseInput( MouseInputEvent ev, MouseButton button, int2 location, Modifiers mods )
|
||||
{
|
||||
this.Event = ev;
|
||||
this.Button = button;
|
||||
this.Location = location;
|
||||
this.Modifiers = mods;
|
||||
}
|
||||
}
|
||||
|
||||
public enum MouseInputEvent { Down, Move, Up };
|
||||
@@ -18,10 +18,9 @@ namespace OpenRA.FileFormats
|
||||
public class Manifest
|
||||
{
|
||||
public readonly string[]
|
||||
Mods, Folders, Packages, Rules,
|
||||
Mods, Folders, Packages, Rules, ServerTraits,
|
||||
Sequences, Cursors, Chrome, Assemblies, ChromeLayout,
|
||||
Weapons, Voices, Music, Movies, TileSets;
|
||||
|
||||
public readonly string ShellmapUid, LoadScreen;
|
||||
public readonly int TileSize = 24;
|
||||
|
||||
@@ -36,6 +35,7 @@ namespace OpenRA.FileFormats
|
||||
Folders = YamlList(yaml, "Folders");
|
||||
Packages = YamlList(yaml, "Packages");
|
||||
Rules = YamlList(yaml, "Rules");
|
||||
ServerTraits = YamlList(yaml, "ServerTraits");
|
||||
Sequences = YamlList(yaml, "Sequences");
|
||||
Cursors = YamlList(yaml, "Cursors");
|
||||
Chrome = YamlList(yaml, "Chrome");
|
||||
|
||||
@@ -17,10 +17,10 @@ namespace OpenRA.FileFormats
|
||||
{
|
||||
public class MapStub
|
||||
{
|
||||
public readonly IFolder Package;
|
||||
public IFolder Container { get; protected set; }
|
||||
|
||||
// Yaml map data
|
||||
public readonly string Uid;
|
||||
public string Uid { get; protected set; }
|
||||
[FieldLoader.Load] public bool Selectable;
|
||||
|
||||
[FieldLoader.Load] public string Title;
|
||||
@@ -37,14 +37,15 @@ namespace OpenRA.FileFormats
|
||||
[FieldLoader.Load] public int2 BottomRight;
|
||||
public int Width { get { return BottomRight.X - TopLeft.X; } }
|
||||
public int Height { get { return BottomRight.Y - TopLeft.Y; } }
|
||||
|
||||
public MapStub(IFolder package)
|
||||
|
||||
public MapStub() {} // Hack for the editor - not used for anything important
|
||||
public MapStub(IFolder container)
|
||||
{
|
||||
Package = package;
|
||||
var yaml = MiniYaml.FromStream(Package.GetContent("map.yaml"));
|
||||
Container = container;
|
||||
var yaml = MiniYaml.FromStream(Container.GetContent("map.yaml"));
|
||||
FieldLoader.Load( this, new MiniYaml( null, yaml ) );
|
||||
|
||||
Uid = Package.GetContent("map.uid").ReadAllText();
|
||||
Uid = Container.GetContent("map.uid").ReadAllText();
|
||||
}
|
||||
|
||||
static object LoadWaypoints( MiniYaml y )
|
||||
|
||||
@@ -16,11 +16,16 @@ namespace OpenRA.FileFormats
|
||||
{
|
||||
public string Name;
|
||||
public string Palette;
|
||||
public string Race;
|
||||
public bool OwnsWorld = false;
|
||||
public bool NonCombatant = false;
|
||||
public bool Playable = false;
|
||||
public bool DefaultStartingUnits = false;
|
||||
public bool AllowBots = true;
|
||||
|
||||
public bool LockRace = false;
|
||||
public string Race;
|
||||
|
||||
public bool LockColor = false;
|
||||
public Color Color = Color.FromArgb(238,238,238);
|
||||
public Color Color2 = Color.FromArgb(44,28,24);
|
||||
|
||||
|
||||
39
OpenRA.FileFormats/Mod.cs
Normal file
39
OpenRA.FileFormats/Mod.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
public class Mod
|
||||
{
|
||||
public string Title;
|
||||
public string Description;
|
||||
public string Version;
|
||||
public string Author;
|
||||
public string[] RequiresMods;
|
||||
public bool Standalone = false;
|
||||
|
||||
public static readonly Dictionary<string, Mod> AllMods = ValidateMods(Directory.GetDirectories("mods").Select(x => x.Substring(5)).ToArray());
|
||||
|
||||
public static Dictionary<string, Mod> ValidateMods(string[] mods)
|
||||
{
|
||||
var ret = new Dictionary<string, Mod>();
|
||||
foreach (var m in mods)
|
||||
{
|
||||
if (!File.Exists("mods" + Path.DirectorySeparatorChar + m + Path.DirectorySeparatorChar + "mod.yaml"))
|
||||
continue;
|
||||
|
||||
var yaml = new MiniYaml(null, MiniYaml.FromFile("mods" + Path.DirectorySeparatorChar + m + Path.DirectorySeparatorChar + "mod.yaml"));
|
||||
if (!yaml.NodesDict.ContainsKey("Metadata"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ret.Add(m, FieldLoader.Load<Mod>(yaml.NodesDict["Metadata"]));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>9.0.21022</ProductVersion>
|
||||
<ProductVersion>9.0.30729</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{BDAEAB25-991E-46A7-AF1E-4F0E03358DAA}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
@@ -45,6 +45,7 @@
|
||||
</Reference>
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="Tao.Sdl, Version=1.2.13.0, Culture=neutral, PublicKeyToken=9c7a200e36c0094e">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
@@ -58,15 +59,13 @@
|
||||
<Compile Include="Evaluator.cs" />
|
||||
<Compile Include="Exts.cs" />
|
||||
<Compile Include="FieldLoader.cs" />
|
||||
<Compile Include="FileSystem.cs" />
|
||||
<Compile Include="Folder.cs" />
|
||||
<Compile Include="Graphics\IGraphicsDevice.cs" />
|
||||
<Compile Include="Graphics\IInputHandler.cs" />
|
||||
<Compile Include="Graphics\Vertex.cs" />
|
||||
<Compile Include="Manifest.cs" />
|
||||
<Compile Include="MiniYaml.cs" />
|
||||
<Compile Include="Mod.cs" />
|
||||
<Compile Include="PackageEntry.cs" />
|
||||
<Compile Include="Package.cs" />
|
||||
<Compile Include="PackageWriter.cs" />
|
||||
<Compile Include="Palette.cs" />
|
||||
<Compile Include="PlayerColorRemap.cs" />
|
||||
<Compile Include="Primitives\DisposableAction.cs" />
|
||||
@@ -98,8 +97,14 @@
|
||||
<Compile Include="Map\MapStub.cs" />
|
||||
<Compile Include="Map\SmudgeReference.cs" />
|
||||
<Compile Include="Map\PlayerReference.cs" />
|
||||
<Compile Include="CompressedPackage.cs" />
|
||||
<Compile Include="Graphics\VqaReader.cs" />
|
||||
<Compile Include="Filesystem\MixFile.cs" />
|
||||
<Compile Include="Filesystem\FileSystem.cs" />
|
||||
<Compile Include="Filesystem\Folder.cs" />
|
||||
<Compile Include="Filesystem\PackageWriter.cs" />
|
||||
<Compile Include="Filesystem\CompressedPackage.cs" />
|
||||
<Compile Include="Filesystem\InstallShieldPackage.cs" />
|
||||
<Compile Include="FileFormats\Blast.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
@@ -109,4 +114,7 @@
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
<ItemGroup>
|
||||
<Folder Include="Filesystem\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
2
OpenRA.FileFormats/PlayerColorRemap.cs
Normal file → Executable file
2
OpenRA.FileFormats/PlayerColorRemap.cs
Normal file → Executable file
@@ -32,7 +32,7 @@ namespace OpenRA.FileFormats
|
||||
.ToDictionary(u => u.First, u => u.Second);
|
||||
}
|
||||
|
||||
static Color ColorLerp(float t, Color c1, Color c2)
|
||||
public static Color ColorLerp(float t, Color c1, Color c2)
|
||||
{
|
||||
return Color.FromArgb(255,
|
||||
(int)(t * c2.R + (1 - t) * c1.R),
|
||||
|
||||
@@ -62,7 +62,8 @@ namespace OpenRA
|
||||
Constrain(Y, min.Y, max.Y));
|
||||
}
|
||||
|
||||
public static float2 operator *(float a, float2 b) { return new float2(a * b.X, a * b.Y); }
|
||||
public static float2 operator *(float a, float2 b) { return new float2(a * b.X, a * b.Y); }
|
||||
public static float2 operator *(float2 b, float a) { return new float2(a * b.X, a * b.Y); }
|
||||
public static float2 operator *( float2 a, float2 b ) { return new float2( a.X * b.X, a.Y * b.Y ); }
|
||||
public static float2 operator /( float2 a, float2 b ) { return new float2( a.X / b.X, a.Y / b.Y ); }
|
||||
|
||||
|
||||
@@ -27,6 +27,8 @@ namespace OpenRA
|
||||
public static int2 operator *(int2 b, int a) { return new int2(a * b.X, a * b.Y); }
|
||||
public static int2 operator /(int2 a, int b) { return new int2(a.X / b, a.Y / b); }
|
||||
|
||||
public static int2 operator -(int2 a) { return new int2(-a.X, -a.Y); }
|
||||
|
||||
public static bool operator ==(int2 me, int2 other) { return (me.X == other.X && me.Y == other.Y); }
|
||||
public static bool operator !=(int2 me, int2 other) { return !(me == other); }
|
||||
|
||||
|
||||
@@ -61,35 +61,19 @@ namespace OpenRA
|
||||
|
||||
// auto size from render
|
||||
var firstSprite = TraitsImplementing<IRender>().SelectMany(x => x.Render(this)).FirstOrDefault();
|
||||
if (firstSprite.Sprite == null) return float2.Zero;
|
||||
return firstSprite.Sprite.size;
|
||||
if (firstSprite.Sprite == null) return float2.Zero;
|
||||
return firstSprite.Sprite.size * firstSprite.Scale;
|
||||
});
|
||||
}
|
||||
|
||||
public void Tick()
|
||||
{
|
||||
var wasIdle = currentActivity is Idle;
|
||||
while (currentActivity != null)
|
||||
{
|
||||
var a = currentActivity;
|
||||
|
||||
var sw = new Stopwatch();
|
||||
currentActivity = a.Tick(this) ?? new Idle();
|
||||
var dt = sw.ElapsedTime();
|
||||
if(dt > Game.Settings.Debug.LongTickThreshold)
|
||||
Log.Write("perf", "[{2}] Activity: {0} ({1:0.000} ms)", a, dt * 1000, Game.LocalTick);
|
||||
|
||||
if (a == currentActivity) break;
|
||||
var wasIdle = currentActivity is Idle;
|
||||
currentActivity = Util.RunActivity( this, currentActivity ) ?? new Idle();
|
||||
|
||||
if (currentActivity is Idle)
|
||||
{
|
||||
if (!wasIdle)
|
||||
foreach (var ni in TraitsImplementing<INotifyIdle>())
|
||||
ni.Idle(this);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (currentActivity is Idle && !wasIdle)
|
||||
foreach (var ni in TraitsImplementing<INotifyIdle>())
|
||||
ni.Idle(this);
|
||||
}
|
||||
|
||||
public bool IsIdle
|
||||
@@ -110,7 +94,13 @@ namespace OpenRA
|
||||
{
|
||||
var si = Info.Traits.GetOrDefault<SelectableInfo>();
|
||||
|
||||
var size = Size.Value;
|
||||
var size = Size.Value;
|
||||
|
||||
/* apply scaling */
|
||||
var scale = this.TraitOrDefault<Scale>();
|
||||
if (scale != null && scale.Info.Value != 1)
|
||||
size = size*scale.Info.Value;
|
||||
|
||||
var loc = CenterLocation - 0.5f * size;
|
||||
|
||||
if (si != null && si.Bounds != null && si.Bounds.Length > 2)
|
||||
@@ -125,7 +115,14 @@ namespace OpenRA
|
||||
return new RectangleF(loc.X, loc.Y, size.X, size.Y);
|
||||
}
|
||||
|
||||
public bool IsInWorld { get; internal set; }
|
||||
public bool IsInWorld { get; internal set; }
|
||||
|
||||
public void QueueActivity( bool queued, IActivity nextActivity )
|
||||
{
|
||||
if( !queued )
|
||||
CancelActivity();
|
||||
QueueActivity( nextActivity );
|
||||
}
|
||||
|
||||
public void QueueActivity( IActivity nextActivity )
|
||||
{
|
||||
@@ -194,6 +191,8 @@ namespace OpenRA
|
||||
{
|
||||
World.AddFrameEndTask( w =>
|
||||
{
|
||||
if (Destroyed) return;
|
||||
|
||||
World.Remove( this );
|
||||
World.traitDict.RemoveActor( this );
|
||||
Destroyed = true;
|
||||
|
||||
@@ -12,7 +12,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Support;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
|
||||
126
OpenRA.Game/Game.cs
Normal file → Executable file
126
OpenRA.Game/Game.cs
Normal file → Executable file
@@ -13,6 +13,7 @@ using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Windows.Forms;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.GameRules;
|
||||
@@ -37,18 +38,19 @@ namespace OpenRA
|
||||
public static Settings Settings;
|
||||
|
||||
internal static OrderManager orderManager;
|
||||
static Server.Server server;
|
||||
|
||||
public static XRandom CosmeticRandom = new XRandom(); // not synced
|
||||
|
||||
public static Renderer Renderer;
|
||||
public static bool HasInputFocus = false;
|
||||
|
||||
public static void MoveViewport(int2 loc)
|
||||
public static void MoveViewport(float2 loc)
|
||||
{
|
||||
viewport.Center(loc);
|
||||
}
|
||||
|
||||
internal static void JoinServer(string host, int port)
|
||||
public static void JoinServer(string host, int port)
|
||||
{
|
||||
if (orderManager != null) orderManager.Dispose();
|
||||
|
||||
@@ -79,7 +81,7 @@ namespace OpenRA
|
||||
internal static int LocalTick { get { return orderManager.LocalFrameNumber; } }
|
||||
const int NetTickScale = 3; // 120ms net tick for 40ms local tick
|
||||
|
||||
internal static event Action<OrderManager> ConnectionStateChanged = _ => { };
|
||||
public static event Action<OrderManager> ConnectionStateChanged = _ => { };
|
||||
static ConnectionState lastConnectionState = ConnectionState.PreConnecting;
|
||||
public static int LocalClientId { get { return orderManager.Connection.LocalClientId; } }
|
||||
|
||||
@@ -98,7 +100,7 @@ namespace OpenRA
|
||||
using (new PerfSample("render"))
|
||||
{
|
||||
++RenderFrame;
|
||||
viewport.DrawRegions(worldRenderer);
|
||||
viewport.DrawRegions(worldRenderer, new DefaultInputHandler( orderManager.world ));
|
||||
Sound.SetListenerPosition(viewport.Location + .5f * new float2(viewport.Width, viewport.Height));
|
||||
}
|
||||
|
||||
@@ -135,10 +137,13 @@ namespace OpenRA
|
||||
|
||||
if( isNetTick ) orderManager.Tick();
|
||||
|
||||
world.OrderGenerator.Tick( world );
|
||||
world.Selection.Tick( world );
|
||||
Sync.CheckSyncUnchanged(world, () =>
|
||||
{
|
||||
world.OrderGenerator.Tick(world);
|
||||
world.Selection.Tick(world);
|
||||
});
|
||||
|
||||
world.Tick();
|
||||
worldRenderer.Tick();
|
||||
|
||||
PerfHistory.Tick();
|
||||
}
|
||||
@@ -148,7 +153,8 @@ namespace OpenRA
|
||||
}
|
||||
}
|
||||
|
||||
internal static event Action LobbyInfoChanged = () => { };
|
||||
public static event Action LobbyInfoChanged = () => { };
|
||||
public static event Action ConnectedToLobby = () => { };
|
||||
|
||||
internal static void SyncLobbyInfo()
|
||||
{
|
||||
@@ -162,7 +168,7 @@ namespace OpenRA
|
||||
BeforeGameStart();
|
||||
|
||||
var map = modData.PrepareMap(mapUID);
|
||||
viewport = new Viewport(new float2(Renderer.Resolution), map.TopLeft, map.BottomRight, Renderer);
|
||||
viewport = new Viewport(new int2(Renderer.Resolution), map.TopLeft, map.BottomRight, Renderer);
|
||||
orderManager.world = new World(modData.Manifest, map, orderManager);
|
||||
worldRenderer = new WorldRenderer(orderManager.world);
|
||||
|
||||
@@ -170,43 +176,19 @@ namespace OpenRA
|
||||
Widget.SelectedWidget = null;
|
||||
|
||||
orderManager.LocalFrameNumber = 0;
|
||||
|
||||
orderManager.StartGame();
|
||||
worldRenderer.RefreshPalette();
|
||||
AfterGameStart( orderManager.world );
|
||||
}
|
||||
|
||||
public static void DispatchMouseInput(MouseInputEvent ev, MouseEventArgs e, Modifiers modifierKeys)
|
||||
{
|
||||
Sync.CheckSyncUnchanged( orderManager.world, () =>
|
||||
{
|
||||
var mi = new MouseInput
|
||||
{
|
||||
Button = (MouseButton)(int)e.Button,
|
||||
Event = ev,
|
||||
Location = new int2( e.Location ),
|
||||
Modifiers = modifierKeys,
|
||||
};
|
||||
Widget.HandleInput( mi );
|
||||
} );
|
||||
}
|
||||
|
||||
public static bool IsHost
|
||||
{
|
||||
get { return orderManager.Connection.LocalClientId == 0; }
|
||||
}
|
||||
|
||||
public static void HandleKeyEvent(KeyInput e)
|
||||
{
|
||||
Sync.CheckSyncUnchanged( orderManager.world, () =>
|
||||
{
|
||||
Widget.HandleKeyPress( e );
|
||||
} );
|
||||
}
|
||||
|
||||
static Modifiers modifiers;
|
||||
public static Modifiers GetModifierKeys() { return modifiers; }
|
||||
public static void HandleModifierKeys(Modifiers mods) { modifiers = mods; }
|
||||
internal static void HandleModifierKeys(Modifiers mods) { modifiers = mods; }
|
||||
|
||||
internal static void Initialize(Arguments args)
|
||||
{
|
||||
@@ -218,10 +200,6 @@ namespace OpenRA
|
||||
SupportDir = args.GetValue("SupportDir", defaultSupport);
|
||||
Settings = new Settings(SupportDir + "settings.yaml", args);
|
||||
|
||||
// force master server upgrade -- remove once everyone is switched over.
|
||||
if (Settings.Server.MasterServer == "http://open-ra.org/master/")
|
||||
Settings.Server.MasterServer = "http://master.open-ra.org/";
|
||||
|
||||
Settings.Save();
|
||||
|
||||
Log.LogPath = SupportDir + "Logs" + Path.DirectorySeparatorChar;
|
||||
@@ -235,15 +213,14 @@ namespace OpenRA
|
||||
Renderer = new Renderer();
|
||||
|
||||
Console.WriteLine("Available mods:");
|
||||
foreach(var mod in ModData.AllMods)
|
||||
foreach(var mod in Mod.AllMods)
|
||||
Console.WriteLine("\t{0}: {1} ({2})", mod.Key, mod.Value.Title, mod.Value.Version);
|
||||
|
||||
// Discard any invalid mods
|
||||
var mods = Settings.Game.Mods.Where( m => ModData.AllMods.ContainsKey( m ) ).ToArray();
|
||||
var mods = Settings.Game.Mods.Where( m => Mod.AllMods.ContainsKey( m ) ).ToArray();
|
||||
Console.WriteLine("Loading mods: {0}",string.Join(",",mods));
|
||||
|
||||
modData = new ModData( mods );
|
||||
|
||||
Sound.Initialize();
|
||||
PerfHistory.items["render"].hasNormalTick = false;
|
||||
PerfHistory.items["batches"].hasNormalTick = false;
|
||||
@@ -254,35 +231,7 @@ namespace OpenRA
|
||||
JoinLocal();
|
||||
StartGame(modData.Manifest.ShellmapUid);
|
||||
|
||||
Game.AfterGameStart += world => Widget.OpenWindow("INGAME_ROOT", new Dictionary<string,object>{{"world", world},{"orderManager",orderManager}});
|
||||
|
||||
Game.ConnectionStateChanged += orderManager =>
|
||||
{
|
||||
Widget.CloseWindow();
|
||||
switch( orderManager.Connection.ConnectionState )
|
||||
{
|
||||
case ConnectionState.PreConnecting:
|
||||
Widget.OpenWindow("MAINMENU_BG");
|
||||
break;
|
||||
case ConnectionState.Connecting:
|
||||
Widget.OpenWindow( "CONNECTING_BG",
|
||||
new Dictionary<string, object> { { "host", orderManager.Host }, { "port", orderManager.Port } } );
|
||||
break;
|
||||
case ConnectionState.NotConnected:
|
||||
Widget.OpenWindow( "CONNECTION_FAILED_BG",
|
||||
new Dictionary<string, object> { { "host", orderManager.Host }, { "port", orderManager.Port } } );
|
||||
break;
|
||||
case ConnectionState.Connected:
|
||||
var lobby = Widget.OpenWindow( "SERVER_LOBBY", new Dictionary<string, object> { { "orderManager", orderManager } } );
|
||||
lobby.GetWidget<ChatDisplayWidget>("CHAT_DISPLAY").ClearChat();
|
||||
lobby.GetWidget("CHANGEMAP_BUTTON").Visible = true;
|
||||
lobby.GetWidget("LOCKTEAMS_CHECKBOX").Visible = true;
|
||||
lobby.GetWidget("DISCONNECT_BUTTON").Visible = true;
|
||||
//r.GetWidget("INGAME_ROOT").GetWidget<ChatDisplayWidget>("CHAT_DISPLAY").ClearChat();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: unhardcode this
|
||||
modData.WidgetLoader.LoadWidget( new Dictionary<string,object>(), Widget.RootWidget, "PERF_BG" );
|
||||
Widget.OpenWindow("MAINMENU_BG");
|
||||
|
||||
@@ -310,6 +259,9 @@ namespace OpenRA
|
||||
|
||||
public static void Disconnect()
|
||||
{
|
||||
if (IsHost && server != null)
|
||||
server.Shutdown();
|
||||
|
||||
orderManager.Dispose();
|
||||
var shellmap = modData.Manifest.ShellmapUid;
|
||||
JoinLocal();
|
||||
@@ -342,5 +294,39 @@ namespace OpenRA
|
||||
{
|
||||
return modData.ObjectCreator.CreateObject<T>( name );
|
||||
}
|
||||
|
||||
public static void RejoinLobby(World world)
|
||||
{
|
||||
var map = orderManager.LobbyInfo.GlobalSettings.Map;
|
||||
var host = orderManager.Host;
|
||||
var port = orderManager.Port;
|
||||
var isHost = Game.IsHost;
|
||||
|
||||
Disconnect();
|
||||
ConnectedToLobby += () =>
|
||||
{
|
||||
if (world.LocalPlayer != null)
|
||||
{
|
||||
/* Try to get back the old slot */
|
||||
Game.orderManager.IssueOrder(Order.Command("race " + world.LocalPlayer.Country.Race));
|
||||
Game.orderManager.IssueOrder(Order.Command("slot " + world.LobbyInfo.ClientWithIndex(world.LocalPlayer.ClientIndex).Slot));
|
||||
}else /* a spectator */
|
||||
{
|
||||
Game.orderManager.IssueOrder(Order.Command("spectator"));
|
||||
}
|
||||
|
||||
ConnectedToLobby = null;
|
||||
};
|
||||
if (isHost)
|
||||
CreateAndJoinServer( Settings, map );
|
||||
else
|
||||
JoinServer(host, port);
|
||||
}
|
||||
|
||||
public static void CreateAndJoinServer(Settings settings, string map)
|
||||
{
|
||||
server = new Server.Server(modData, settings, map);
|
||||
JoinServer(IPAddress.Loopback.ToString(), settings.Server.ListenPort);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,21 +66,21 @@ namespace OpenRA
|
||||
var ret = new List<ITraitInfo>();
|
||||
var t = Traits.WithInterface<ITraitInfo>().ToList();
|
||||
int index = 0;
|
||||
while( t.Count != 0 )
|
||||
while (t.Count != 0)
|
||||
{
|
||||
if( index >= t.Count )
|
||||
throw new InvalidOperationException( "Trait prerequisites not satisfied (or prerequisite loop) Actor={0} Unresolved={1}".F(
|
||||
Name, string.Join( ",", t.Select( x => x.GetType().Name ).ToArray())));
|
||||
|
||||
var prereqs = PrerequisitesOf( t[ index ] );
|
||||
if( prereqs.Count == 0 || prereqs.All( n => ret.Any( x => x.GetType() == n || x.GetType().IsSubclassOf( n ) ) ) )
|
||||
var prereqs = PrerequisitesOf(t[index]);
|
||||
var unsatisfied = prereqs.Where(n => !ret.Any(x => x.GetType() == n || x.GetType().IsSubclassOf(n)));
|
||||
if (!unsatisfied.Any())
|
||||
{
|
||||
ret.Add( t[ index ] );
|
||||
t.RemoveAt( index );
|
||||
ret.Add(t[index]);
|
||||
t.RemoveAt(index);
|
||||
index = 0;
|
||||
}
|
||||
else
|
||||
++index;
|
||||
else if (++index >= t.Count)
|
||||
throw new InvalidOperationException("Trait prerequisites not satisfied (or prerequisite loop) Actor={0} Unresolved={1} Missing={2}".F(
|
||||
Name,
|
||||
string.Join(",", t.Select(x => x.GetType().Name).ToArray()),
|
||||
string.Join(",", unsatisfied.Select(x => x.Name).ToArray())));
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -27,6 +27,7 @@ namespace OpenRA
|
||||
|
||||
public static void LoadRules(Manifest m, Map map)
|
||||
{
|
||||
// Added support to extend the list of rules (add it to m.LocalRules)
|
||||
Info = LoadYamlRules(m.Rules, map.Rules, (k, y) => new ActorInfo(k.Key.ToLowerInvariant(), k.Value, y));
|
||||
Weapons = LoadYamlRules(m.Weapons, new List<MiniYamlNode>(), (k, _) => new WeaponInfo(k.Key.ToLowerInvariant(), k.Value));
|
||||
Voices = LoadYamlRules(m.Voices, new List<MiniYamlNode>(), (k, _) => new VoiceInfo(k.Value));
|
||||
|
||||
@@ -15,6 +15,7 @@ using System.IO;
|
||||
using System.Windows.Forms;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.FileFormats.Graphics;
|
||||
using OpenRA.Server;
|
||||
|
||||
namespace OpenRA.GameRules
|
||||
{
|
||||
@@ -30,17 +31,17 @@ namespace OpenRA.GameRules
|
||||
|
||||
public class DebugSettings
|
||||
{
|
||||
public bool BotDebug = false;
|
||||
public bool PerfGraph = false;
|
||||
public bool RecordSyncReports = true;
|
||||
public bool ShowCollisions = false;
|
||||
public float LongTickThreshold = 0.001f;
|
||||
}
|
||||
|
||||
|
||||
public class GraphicSettings
|
||||
{
|
||||
public WindowMode Mode = WindowMode.PseudoFullscreen;
|
||||
public int2 FullscreenSize = new int2(Screen.PrimaryScreen.Bounds.Width,Screen.PrimaryScreen.Bounds.Height);
|
||||
public int2 WindowedSize = new int2(1024,768);
|
||||
public int2 FullscreenSize = new int2(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
|
||||
public int2 WindowedSize = new int2(1024, 768);
|
||||
public readonly int2 MinResolution = new int2(800, 600);
|
||||
}
|
||||
|
||||
@@ -66,6 +67,9 @@ namespace OpenRA.GameRules
|
||||
public string[] Mods = { "ra" };
|
||||
public bool MatchTimer = true;
|
||||
|
||||
// Chat settings
|
||||
public bool TeamChatToggle = false;
|
||||
|
||||
// Behaviour settings
|
||||
public bool ViewportEdgeScroll = true;
|
||||
public bool InverseDragScroll = false;
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace OpenRA.Graphics
|
||||
}
|
||||
|
||||
Sprite[] LoadCursors(string filename)
|
||||
{
|
||||
{
|
||||
try
|
||||
{
|
||||
var shp = new Dune2ShpReader(FileSystem.OpenWithExts(filename, exts));
|
||||
|
||||
@@ -135,10 +135,12 @@ namespace OpenRA.Graphics
|
||||
unsafe
|
||||
{
|
||||
int* c = (int*)bitmapData.Scan0;
|
||||
|
||||
|
||||
var player = world.LocalPlayer;
|
||||
|
||||
foreach (var t in world.Queries.WithTraitMultiple<IRadarSignature>())
|
||||
{
|
||||
if (!t.Actor.IsVisible(world.LocalPlayer))
|
||||
if (!t.Actor.IsVisible(player))
|
||||
continue;
|
||||
|
||||
var color = t.Trait.RadarSignatureColor(t.Actor);
|
||||
@@ -162,7 +164,9 @@ namespace OpenRA.Graphics
|
||||
|
||||
var shroud = Color.Black.ToArgb();
|
||||
var fog = Color.FromArgb(128, Color.Black).ToArgb();
|
||||
|
||||
|
||||
var playerShroud = world.LocalPlayer.Shroud;
|
||||
|
||||
unsafe
|
||||
{
|
||||
int* c = (int*)bitmapData.Scan0;
|
||||
@@ -172,9 +176,9 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
var mapX = x + map.TopLeft.X;
|
||||
var mapY = y + map.TopLeft.Y;
|
||||
if (!world.LocalPlayer.Shroud.IsExplored(mapX, mapY))
|
||||
if (!playerShroud.IsExplored(mapX, mapY))
|
||||
*(c + (y * bitmapData.Stride >> 2) + x) = shroud;
|
||||
else if (!world.LocalPlayer.Shroud.IsVisible(mapX,mapY))
|
||||
else if (!playerShroud.IsVisible(mapX,mapY))
|
||||
*(c + (y * bitmapData.Stride >> 2) + x) = fog;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Windows.Forms;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.FileFormats.Graphics;
|
||||
using OpenRA.Support;
|
||||
using System.Windows.Forms;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
@@ -71,7 +71,6 @@ namespace OpenRA.Graphics
|
||||
|
||||
public void BeginFrame(float2 scroll)
|
||||
{
|
||||
device.Begin();
|
||||
device.Clear(Color.Black);
|
||||
|
||||
float2 r1 = new float2(2f/Resolution.Width, -2f/Resolution.Height);
|
||||
@@ -86,17 +85,16 @@ namespace OpenRA.Graphics
|
||||
private void SetShaderParams( IShader s, float2 r1, float2 r2, float2 scroll )
|
||||
{
|
||||
s.SetValue( "Palette", PaletteTexture );
|
||||
s.SetValue( "Scroll", scroll.X, scroll.Y );
|
||||
s.SetValue( "Scroll", (int) scroll.X, (int) scroll.Y );
|
||||
s.SetValue( "r1", r1.X, r1.Y );
|
||||
s.SetValue( "r2", r2.X, r2.Y );
|
||||
s.Commit();
|
||||
}
|
||||
|
||||
public void EndFrame()
|
||||
public void EndFrame( IInputHandler inputHandler )
|
||||
{
|
||||
Flush();
|
||||
device.End();
|
||||
device.Present();
|
||||
device.Present( inputHandler );
|
||||
}
|
||||
|
||||
public void DrawBatch<T>(IVertexBuffer<T> vertices, IIndexBuffer indices,
|
||||
|
||||
@@ -60,6 +60,11 @@ namespace OpenRA.Graphics
|
||||
Game.Renderer.SpriteRenderer.DrawSprite( this, location, paletteIndex, this.size );
|
||||
}
|
||||
|
||||
public void DrawAt(float2 location, int paletteIndex, float scale)
|
||||
{
|
||||
Game.Renderer.SpriteRenderer.DrawSprite(this, location, paletteIndex, this.size * scale);
|
||||
}
|
||||
|
||||
public void DrawAt( float2 location, int paletteIndex, float2 size )
|
||||
{
|
||||
Game.Renderer.SpriteRenderer.DrawSprite( this, location, paletteIndex, size );
|
||||
|
||||
29
OpenRA.Game/Graphics/Viewport.cs
Normal file → Executable file
29
OpenRA.Game/Graphics/Viewport.cs
Normal file → Executable file
@@ -18,16 +18,16 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
public class Viewport
|
||||
{
|
||||
readonly float2 screenSize;
|
||||
float2 scrollPosition;
|
||||
readonly int2 screenSize;
|
||||
int2 scrollPosition;
|
||||
readonly Renderer renderer;
|
||||
readonly int2 mapStart;
|
||||
readonly int2 mapEnd;
|
||||
|
||||
public float2 Location { get { return scrollPosition; } }
|
||||
|
||||
public int Width { get { return (int)screenSize.X; } }
|
||||
public int Height { get { return (int)screenSize.Y; } }
|
||||
public int Width { get { return screenSize.X; } }
|
||||
public int Height { get { return screenSize.Y; } }
|
||||
|
||||
float cursorFrame = 0f;
|
||||
|
||||
@@ -41,7 +41,8 @@ namespace OpenRA.Graphics
|
||||
|
||||
public void Scroll(float2 delta, bool ignoreBorders)
|
||||
{
|
||||
float2 newScrollPosition = scrollPosition + delta;
|
||||
var d = delta.ToInt2();
|
||||
var newScrollPosition = scrollPosition + d;
|
||||
|
||||
if(!ignoreBorders)
|
||||
newScrollPosition = this.NormalizeScrollPosition(newScrollPosition);
|
||||
@@ -49,10 +50,10 @@ namespace OpenRA.Graphics
|
||||
scrollPosition = newScrollPosition;
|
||||
}
|
||||
|
||||
private float2 NormalizeScrollPosition(float2 newScrollPosition)
|
||||
private int2 NormalizeScrollPosition(int2 newScrollPosition)
|
||||
{
|
||||
float2 topLeftBorder = (Game.CellSize* mapStart).ToFloat2();
|
||||
float2 bottomRightBorder = (Game.CellSize* mapEnd).ToFloat2();
|
||||
var topLeftBorder = Game.CellSize* mapStart;
|
||||
var bottomRightBorder = Game.CellSize* mapEnd;
|
||||
|
||||
if(newScrollPosition.Y < topLeftBorder.Y - screenSize.Y/2)
|
||||
newScrollPosition.Y = topLeftBorder.Y - screenSize.Y/2;
|
||||
@@ -85,7 +86,7 @@ namespace OpenRA.Graphics
|
||||
return blockedDirections;
|
||||
}
|
||||
|
||||
public Viewport(float2 screenSize, int2 mapStart, int2 mapEnd, Renderer renderer)
|
||||
public Viewport(int2 screenSize, int2 mapStart, int2 mapEnd, Renderer renderer)
|
||||
{
|
||||
this.screenSize = screenSize;
|
||||
this.renderer = renderer;
|
||||
@@ -95,7 +96,7 @@ namespace OpenRA.Graphics
|
||||
this.scrollPosition = Game.CellSize* mapStart;
|
||||
}
|
||||
|
||||
public void DrawRegions( WorldRenderer wr )
|
||||
public void DrawRegions( WorldRenderer wr, IInputHandler inputHandler )
|
||||
{
|
||||
renderer.BeginFrame(scrollPosition);
|
||||
wr.Draw();
|
||||
@@ -106,7 +107,7 @@ namespace OpenRA.Graphics
|
||||
var c = new Cursor(cursorName);
|
||||
c.Draw(wr, (int)cursorFrame, Viewport.LastMousePos + Location);
|
||||
|
||||
renderer.EndFrame();
|
||||
renderer.EndFrame( inputHandler );
|
||||
}
|
||||
|
||||
public void Tick()
|
||||
@@ -123,9 +124,9 @@ namespace OpenRA.Graphics
|
||||
return ViewToWorld(mi.Location);
|
||||
}
|
||||
|
||||
public void Center(int2 loc)
|
||||
public void Center(float2 loc)
|
||||
{
|
||||
scrollPosition = this.NormalizeScrollPosition(Game.CellSize*loc - .5f * new float2(Width, Height));
|
||||
scrollPosition = this.NormalizeScrollPosition((Game.CellSize*loc - screenSize / 2).ToInt2());
|
||||
}
|
||||
|
||||
public void Center(IEnumerable<Actor> actors)
|
||||
@@ -136,7 +137,7 @@ namespace OpenRA.Graphics
|
||||
.Select(a => a.CenterLocation)
|
||||
.Aggregate((a, b) => a + b);
|
||||
|
||||
scrollPosition = this.NormalizeScrollPosition((avgPos - .5f * new float2(Width, Height)));
|
||||
scrollPosition = this.NormalizeScrollPosition((avgPos.ToInt2() - screenSize / 2));
|
||||
}
|
||||
|
||||
public Rectangle ShroudBounds( World world )
|
||||
|
||||
@@ -70,8 +70,7 @@ namespace OpenRA.Graphics
|
||||
return new Rectangle(0, 0, Game.viewport.Width, Game.viewport.Height);
|
||||
}
|
||||
|
||||
Renderable[] worldSprites = { };
|
||||
public void Tick()
|
||||
IEnumerable<Renderable> SpritesToRender()
|
||||
{
|
||||
var bounds = GetBoundsRect();
|
||||
var comparer = new SpriteComparer();
|
||||
@@ -87,7 +86,7 @@ namespace OpenRA.Graphics
|
||||
|
||||
var effects = world.Effects.SelectMany(e => e.Render());
|
||||
|
||||
worldSprites = renderables.Concat(effects).ToArray();
|
||||
return renderables.Concat(effects);
|
||||
}
|
||||
|
||||
public void Draw()
|
||||
@@ -100,10 +99,16 @@ namespace OpenRA.Graphics
|
||||
|
||||
if (world.OrderGenerator != null)
|
||||
world.OrderGenerator.RenderBeforeWorld(this, world);
|
||||
|
||||
foreach (var image in SpritesToRender() )
|
||||
image.Sprite.DrawAt(image.Pos, this.GetPaletteIndex(image.Palette), image.Scale);
|
||||
uiOverlay.Draw(this, world);
|
||||
|
||||
foreach( var image in worldSprites )
|
||||
image.Sprite.DrawAt( image.Pos, this.GetPaletteIndex( image.Palette ) );
|
||||
uiOverlay.Draw(this, world);
|
||||
// added for contrails
|
||||
foreach (var a in world.Actors)
|
||||
if (!a.Destroyed)
|
||||
foreach (var t in a.TraitsImplementing<IPostRender>())
|
||||
t.RenderAfterWorld(this, a);
|
||||
|
||||
if (world.OrderGenerator != null)
|
||||
world.OrderGenerator.RenderAfterWorld(this, world);
|
||||
|
||||
52
OpenRA.Game/InputHandler.cs
Executable file
52
OpenRA.Game/InputHandler.cs
Executable file
@@ -0,0 +1,52 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
public class NullInputHandler : IInputHandler
|
||||
{
|
||||
// ignore all input
|
||||
public void ModifierKeys( Modifiers mods ) { }
|
||||
public void OnKeyInput( KeyInput input ) { }
|
||||
public void OnMouseInput( MouseInput input ) { }
|
||||
}
|
||||
|
||||
public class DefaultInputHandler : IInputHandler
|
||||
{
|
||||
readonly World world;
|
||||
public DefaultInputHandler( World world )
|
||||
{
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
public void ModifierKeys( Modifiers mods )
|
||||
{
|
||||
Game.HandleModifierKeys( mods );
|
||||
}
|
||||
|
||||
public void OnKeyInput( KeyInput input )
|
||||
{
|
||||
Sync.CheckSyncUnchanged( world, () =>
|
||||
{
|
||||
Widget.HandleKeyPress( input );
|
||||
} );
|
||||
}
|
||||
|
||||
public void OnMouseInput( MouseInput input )
|
||||
{
|
||||
Sync.CheckSyncUnchanged( world, () =>
|
||||
{
|
||||
Widget.HandleInput( input );
|
||||
} );
|
||||
}
|
||||
}
|
||||
}
|
||||
44
OpenRA.Game/Map.cs
Executable file → Normal file
44
OpenRA.Game/Map.cs
Executable file → Normal file
@@ -19,24 +19,14 @@ using OpenRA.FileFormats;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
public class Map
|
||||
public class Map : MapStub
|
||||
{
|
||||
public IFolder Package;
|
||||
public string Uid;
|
||||
|
||||
// Yaml map data
|
||||
[FieldLoader.Load] public bool Selectable = true;
|
||||
[FieldLoader.Load] public int MapFormat;
|
||||
[FieldLoader.Load] public string Title;
|
||||
[FieldLoader.Load] public string Description;
|
||||
[FieldLoader.Load] public string Author;
|
||||
[FieldLoader.Load] public int PlayerCount;
|
||||
[FieldLoader.Load] public string Tileset;
|
||||
|
||||
public Dictionary<string, PlayerReference> Players = new Dictionary<string, PlayerReference>();
|
||||
public Dictionary<string, ActorReference> Actors = new Dictionary<string, ActorReference>();
|
||||
public List<SmudgeReference> Smudges = new List<SmudgeReference>();
|
||||
public Dictionary<string, int2> Waypoints = new Dictionary<string, int2>();
|
||||
|
||||
// Rules overrides
|
||||
public List<MiniYamlNode> Rules = new List<MiniYamlNode>();
|
||||
@@ -45,8 +35,6 @@ namespace OpenRA
|
||||
public byte TileFormat = 1;
|
||||
[FieldLoader.Load] public int2 MapSize;
|
||||
|
||||
[FieldLoader.Load] public int2 TopLeft;
|
||||
[FieldLoader.Load] public int2 BottomRight;
|
||||
|
||||
public TileReference<ushort, byte>[,] MapTiles;
|
||||
public TileReference<byte, byte>[,] MapResources;
|
||||
@@ -55,10 +43,7 @@ namespace OpenRA
|
||||
// Temporary compat hacks
|
||||
public int XOffset { get { return TopLeft.X; } }
|
||||
public int YOffset { get { return TopLeft.Y; } }
|
||||
public int Width { get { return BottomRight.X - TopLeft.X; } }
|
||||
public int Height { get { return BottomRight.Y - TopLeft.Y; } }
|
||||
public string Theater { get { return Tileset; } }
|
||||
public IEnumerable<int2> SpawnPoints { get { return Waypoints.Select(kv => kv.Value); } }
|
||||
public Rectangle Bounds { get { return Rectangle.FromLTRB(TopLeft.X, TopLeft.Y, BottomRight.X, BottomRight.Y); } }
|
||||
|
||||
public Map()
|
||||
@@ -95,21 +80,16 @@ namespace OpenRA
|
||||
public int2 Location = int2.Zero;
|
||||
public string Owner = null;
|
||||
}
|
||||
|
||||
|
||||
public Map(MapStub stub) : this(stub.Container) {}
|
||||
public Map(IFolder package)
|
||||
: base(package)
|
||||
{
|
||||
Package = package;
|
||||
var yaml = new MiniYaml( null, MiniYaml.FromStream( Package.GetContent( "map.yaml" ) ) );
|
||||
var yaml = new MiniYaml( null, MiniYaml.FromStream( Container.GetContent( "map.yaml" ) ) );
|
||||
|
||||
// 'Simple' metadata
|
||||
FieldLoader.Load( this, yaml );
|
||||
|
||||
// Waypoints
|
||||
foreach (var wp in yaml.NodesDict["Waypoints"].NodesDict)
|
||||
{
|
||||
string[] loc = wp.Value.Value.Split(',');
|
||||
Waypoints.Add(wp.Key, new int2(int.Parse(loc[0]), int.Parse(loc[1])));
|
||||
}
|
||||
|
||||
// Players & Actors -- this has changed several times.
|
||||
// - Be backwards compatible wherever possible.
|
||||
@@ -199,12 +179,13 @@ namespace OpenRA
|
||||
Rules = yaml.NodesDict["Rules"].Nodes;
|
||||
|
||||
CustomTerrain = new string[MapSize.X, MapSize.Y];
|
||||
LoadUid();
|
||||
LoadBinaryData();
|
||||
}
|
||||
|
||||
public void Save(string filepath)
|
||||
{
|
||||
// Todo: save to a zip file in the support dir by default
|
||||
Container = new Folder(filepath, 0);
|
||||
MapFormat = 3;
|
||||
|
||||
var root = new List<MiniYamlNode>();
|
||||
@@ -252,7 +233,7 @@ namespace OpenRA
|
||||
|
||||
public void LoadBinaryData()
|
||||
{
|
||||
using (var dataStream = Package.GetContent("map.bin"))
|
||||
using (var dataStream = Container.GetContent("map.bin"))
|
||||
{
|
||||
if (ReadByte(dataStream) != 1)
|
||||
throw new InvalidDataException("Unknown binary map format");
|
||||
@@ -314,17 +295,12 @@ namespace OpenRA
|
||||
File.Move(filepath + ".tmp", filepath);
|
||||
}
|
||||
|
||||
public void LoadUid()
|
||||
{
|
||||
Uid = Package.GetContent("map.uid").ReadAllText();
|
||||
}
|
||||
|
||||
public void SaveUid(string filename)
|
||||
{
|
||||
// UID is calculated by taking an SHA1 of the yaml and binary data
|
||||
// Read the relevant data into a buffer
|
||||
var data = Package.GetContent("map.yaml").ReadAllBytes()
|
||||
.Concat(Package.GetContent("map.bin").ReadAllBytes()).ToArray();
|
||||
var data = Container.GetContent("map.yaml").ReadAllBytes()
|
||||
.Concat(Container.GetContent("map.bin").ReadAllBytes()).ToArray();
|
||||
|
||||
// Take the SHA1
|
||||
using (var csp = SHA1.Create())
|
||||
|
||||
@@ -13,44 +13,11 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Support;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
public class ModData
|
||||
{
|
||||
public static readonly Dictionary<string,Mod> AllMods = ValidateMods(Directory.GetDirectories("mods").Select(x => x.Substring(5)).ToArray());
|
||||
|
||||
public static Dictionary<string,Mod> ValidateMods(string[] mods)
|
||||
{
|
||||
var ret = new Dictionary<string,Mod>();
|
||||
foreach (var m in mods)
|
||||
{
|
||||
if (!File.Exists("mods" + Path.DirectorySeparatorChar + m + Path.DirectorySeparatorChar + "mod.yaml"))
|
||||
continue;
|
||||
|
||||
var yaml = new MiniYaml( null, MiniYaml.FromFile("mods" + Path.DirectorySeparatorChar + m + Path.DirectorySeparatorChar + "mod.yaml"));
|
||||
if (!yaml.NodesDict.ContainsKey("Metadata"))
|
||||
{
|
||||
System.Console.WriteLine("Invalid mod: "+m);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret.Add(m,FieldLoader.Load<Mod>(yaml.NodesDict["Metadata"]));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public class Mod
|
||||
{
|
||||
public string Title;
|
||||
public string Description;
|
||||
public string Version;
|
||||
public string Author;
|
||||
public string[] RequiresMods;
|
||||
public bool Standalone = false;
|
||||
}
|
||||
|
||||
public readonly Manifest Manifest;
|
||||
public readonly ObjectCreator ObjectCreator;
|
||||
public readonly SheetBuilder SheetBuilder;
|
||||
@@ -82,7 +49,7 @@ namespace OpenRA
|
||||
.Where(p => Directory.Exists(p))
|
||||
.SelectMany(p => Directory.GetDirectories(p)).ToList();
|
||||
|
||||
return paths.Select(p => new MapStub(new Folder(p))).ToDictionary(m => m.Uid);
|
||||
return paths.Select(p => new MapStub(new Folder(p, 0))).ToDictionary(m => m.Uid);
|
||||
}
|
||||
|
||||
string cachedTheatre = null;
|
||||
@@ -93,7 +60,7 @@ namespace OpenRA
|
||||
if (!AvailableMaps.ContainsKey(uid))
|
||||
throw new InvalidDataException("Invalid map uid: {0}".F(uid));
|
||||
|
||||
var map = new Map(AvailableMaps[uid].Package);
|
||||
var map = new Map(AvailableMaps[uid]);
|
||||
|
||||
Rules.LoadRules(Manifest, map);
|
||||
if (map.Theater != cachedTheatre)
|
||||
|
||||
@@ -18,7 +18,7 @@ using OpenRA.Support;
|
||||
|
||||
namespace OpenRA.Network
|
||||
{
|
||||
enum ConnectionState
|
||||
public enum ConnectionState
|
||||
{
|
||||
PreConnecting,
|
||||
NotConnected,
|
||||
@@ -26,11 +26,13 @@ namespace OpenRA.Network
|
||||
Connected,
|
||||
}
|
||||
|
||||
interface IConnection : IDisposable
|
||||
public interface IConnection : IDisposable
|
||||
{
|
||||
int LocalClientId { get; }
|
||||
ConnectionState ConnectionState { get; }
|
||||
void Send( byte[] packet );
|
||||
void Send( int frame, List<byte[]> orders );
|
||||
void SendImmediate( List<byte[]> orders );
|
||||
void SendSync( int frame, byte[] syncData );
|
||||
void Receive( Action<int, byte[]> packetFn );
|
||||
}
|
||||
|
||||
@@ -53,7 +55,33 @@ namespace OpenRA.Network
|
||||
get { return ConnectionState.PreConnecting; }
|
||||
}
|
||||
|
||||
public virtual void Send( byte[] packet )
|
||||
public virtual void Send( int frame, List<byte[]> orders )
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
ms.Write( BitConverter.GetBytes( frame ) );
|
||||
foreach( var o in orders )
|
||||
ms.Write( o );
|
||||
Send( ms.ToArray() );
|
||||
}
|
||||
|
||||
public virtual void SendImmediate( List<byte[]> orders )
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
ms.Write( BitConverter.GetBytes( (int)0 ) );
|
||||
foreach( var o in orders )
|
||||
ms.Write( o );
|
||||
Send( ms.ToArray() );
|
||||
}
|
||||
|
||||
public virtual void SendSync( int frame, byte[] syncData )
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
ms.Write( BitConverter.GetBytes( frame ) );
|
||||
ms.Write( syncData );
|
||||
Send( ms.ToArray() );
|
||||
}
|
||||
|
||||
protected virtual void Send( byte[] packet )
|
||||
{
|
||||
if( packet.Length == 0 )
|
||||
throw new NotImplementedException();
|
||||
@@ -129,7 +157,17 @@ namespace OpenRA.Network
|
||||
public override int LocalClientId { get { return clientId; } }
|
||||
public override ConnectionState ConnectionState { get { return connectionState; } }
|
||||
|
||||
public override void Send( byte[] packet )
|
||||
List<byte[]> queuedSyncPackets = new List<byte[]>();
|
||||
|
||||
public override void SendSync( int frame, byte[] syncData )
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
ms.Write( BitConverter.GetBytes( frame ) );
|
||||
ms.Write( syncData );
|
||||
queuedSyncPackets.Add( ms.ToArray() );
|
||||
}
|
||||
|
||||
protected override void Send( byte[] packet )
|
||||
{
|
||||
base.Send( packet );
|
||||
|
||||
@@ -138,10 +176,18 @@ namespace OpenRA.Network
|
||||
var ms = new MemoryStream();
|
||||
ms.Write(BitConverter.GetBytes((int)packet.Length));
|
||||
ms.Write(packet);
|
||||
foreach( var q in queuedSyncPackets )
|
||||
{
|
||||
ms.Write( BitConverter.GetBytes( (int)q.Length ) );
|
||||
ms.Write( q );
|
||||
base.Send( q );
|
||||
}
|
||||
queuedSyncPackets.Clear();
|
||||
ms.WriteTo(socket.GetStream());
|
||||
}
|
||||
catch (SocketException) { /* drop this on the floor; we'll pick up the disconnect from the reader thread */ }
|
||||
catch (ObjectDisposedException) { /* ditto */ }
|
||||
catch (InvalidOperationException) { /* ditto */ }
|
||||
}
|
||||
|
||||
bool disposed = false;
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace OpenRA.Network
|
||||
|
||||
public void ClientQuit( int clientId, int lastClientFrame )
|
||||
{
|
||||
clientQuitTimes.Add( clientId, lastClientFrame );
|
||||
clientQuitTimes[clientId] = lastClientFrame;
|
||||
}
|
||||
|
||||
public void AddFrameOrders( int clientId, int frame, byte[] orders )
|
||||
|
||||
@@ -37,22 +37,20 @@ namespace OpenRA
|
||||
this.Queued = queued;
|
||||
}
|
||||
|
||||
public Order(string orderString, Actor subject)
|
||||
: this(orderString, subject, null, int2.Zero, null, false) { }
|
||||
public Order(string orderString, Actor subject, Actor targetActor)
|
||||
: this(orderString, subject, targetActor, int2.Zero, null, false) { }
|
||||
public Order(string orderString, Actor subject, int2 targetLocation)
|
||||
: this(orderString, subject, null, targetLocation, null, false) { }
|
||||
public Order(string orderString, Actor subject, bool queued)
|
||||
: this(orderString, subject, null, int2.Zero, null, queued) { }
|
||||
public Order(string orderString, Actor subject, Actor targetActor, bool queued)
|
||||
: this(orderString, subject, targetActor, int2.Zero, null, queued) { }
|
||||
public Order(string orderString, Actor subject, int2 targetLocation, bool queued)
|
||||
: this(orderString, subject, null, targetLocation, null, queued) { }
|
||||
public Order(string orderString, Actor subject, string targetString)
|
||||
: this(orderString, subject, null, int2.Zero, targetString, false) { }
|
||||
public Order(string orderString, Actor subject, Actor targetActor, int2 targetLocation)
|
||||
: this(orderString, subject, targetActor, targetLocation, null, false) { }
|
||||
public Order(string orderString, Actor subject, Actor targetActor, string targetString)
|
||||
: this(orderString, subject, targetActor, int2.Zero, targetString, false) { }
|
||||
public Order(string orderString, Actor subject, int2 targetLocation, string targetString)
|
||||
: this(orderString, subject, null, targetLocation, targetString, false) { }
|
||||
public Order(string orderString, Actor subject, string targetString, bool queued)
|
||||
: this(orderString, subject, null, int2.Zero, targetString, queued) { }
|
||||
public Order(string orderString, Actor subject, Actor targetActor, int2 targetLocation, bool queued)
|
||||
: this(orderString, subject, targetActor, targetLocation, null, queued) { }
|
||||
public Order(string orderString, Actor subject, Actor targetActor, string targetString, bool queued)
|
||||
: this(orderString, subject, targetActor, int2.Zero, targetString, queued) { }
|
||||
public Order(string orderString, Actor subject, int2 targetLocation, string targetString, bool queued)
|
||||
: this(orderString, subject, null, targetLocation, targetString, queued) { }
|
||||
|
||||
public byte[] Serialize()
|
||||
{
|
||||
@@ -120,7 +118,7 @@ namespace OpenRA
|
||||
var name = r.ReadString();
|
||||
var data = r.ReadString();
|
||||
|
||||
return new Order( name, null, data ) { IsImmediate = true };
|
||||
return new Order( name, null, data, false ) { IsImmediate = true };
|
||||
}
|
||||
|
||||
default:
|
||||
@@ -130,9 +128,9 @@ namespace OpenRA
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "OrderString: \"{0}\" \n\t Subject: \"{1}\". \n\t TargetActor: \"{2}\" \n\t TargetLocation: {3}." +
|
||||
"\n\t TargetString: \"{4}\".\n\t IsImmediate: {5}.\n\t Player(PlayerName): {6}\n".F(
|
||||
OrderString, Subject, TargetActor.Info.Name , TargetLocation, TargetString, IsImmediate, Player.PlayerName);
|
||||
return ("OrderString: \"{0}\" \n\t Subject: \"{1}\". \n\t TargetActor: \"{2}\" \n\t TargetLocation: {3}." +
|
||||
"\n\t TargetString: \"{4}\".\n\t IsImmediate: {5}.\n\t Player(PlayerName): {6}\n").F(
|
||||
OrderString, Subject, TargetActor != null ? TargetActor.Info.Name : null , TargetLocation, TargetString, IsImmediate, Player != null ? Player.PlayerName : null);
|
||||
}
|
||||
|
||||
static uint UIntFromActor(Actor a)
|
||||
@@ -164,32 +162,32 @@ namespace OpenRA
|
||||
// Now that Orders are resolved by individual Actors, these are weird; you unpack orders manually, but not pack them.
|
||||
public static Order Chat(string text)
|
||||
{
|
||||
return new Order("Chat", null, text) { IsImmediate = true };
|
||||
return new Order("Chat", null, text, false) { IsImmediate = true };
|
||||
}
|
||||
|
||||
public static Order TeamChat(string text)
|
||||
{
|
||||
return new Order("TeamChat", null, text) { IsImmediate = true };
|
||||
return new Order("TeamChat", null, text, false) { IsImmediate = true };
|
||||
}
|
||||
|
||||
public static Order Command(string text)
|
||||
{
|
||||
return new Order("Command", null, text) { IsImmediate = true };
|
||||
return new Order("Command", null, text, false) { IsImmediate = true };
|
||||
}
|
||||
|
||||
public static Order StartProduction(Actor subject, string item, int count)
|
||||
{
|
||||
return new Order("StartProduction", subject, new int2( count, 0 ), item );
|
||||
return new Order("StartProduction", subject, new int2( count, 0 ), item, false );
|
||||
}
|
||||
|
||||
public static Order PauseProduction(Actor subject, string item, bool pause)
|
||||
{
|
||||
return new Order("PauseProduction", subject, new int2( pause ? 1 : 0, 0 ), item);
|
||||
return new Order("PauseProduction", subject, new int2( pause ? 1 : 0, 0 ), item, false);
|
||||
}
|
||||
|
||||
public static Order CancelProduction(Actor subject, string item, int count)
|
||||
{
|
||||
return new Order("CancelProduction", subject, new int2( count, 0 ), item);
|
||||
return new Order("CancelProduction", subject, new int2( count, 0 ), item, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,22 +22,6 @@ namespace OpenRA.Network
|
||||
s.Write(buf, 0, buf.Length);
|
||||
}
|
||||
|
||||
public static void WriteFrameData(this Stream s, IEnumerable<Order> orders, int frameNumber)
|
||||
{
|
||||
var bytes = Serialize( orders, frameNumber );
|
||||
s.Write( BitConverter.GetBytes( (int)bytes.Length ) );
|
||||
s.Write( bytes );
|
||||
}
|
||||
|
||||
public static byte[] Serialize( this IEnumerable<Order> orders, int frameNumber )
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
ms.Write( BitConverter.GetBytes( frameNumber ) );
|
||||
foreach( var o in orders.Select( o => o.Serialize() ) )
|
||||
ms.Write( o );
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
public static List<Order> ToOrderList(this byte[] bytes, World world)
|
||||
{
|
||||
var ms = new MemoryStream(bytes, 4, bytes.Length - 4);
|
||||
@@ -52,12 +36,11 @@ namespace OpenRA.Network
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static byte[] SerializeSync( this List<int> sync, int frameNumber )
|
||||
public static byte[] SerializeSync( this List<int> sync )
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
using( var writer = new BinaryWriter( ms ) )
|
||||
{
|
||||
writer.Write( frameNumber );
|
||||
writer.Write( (byte)0x65 );
|
||||
foreach( var s in sync )
|
||||
writer.Write( s );
|
||||
|
||||
@@ -16,7 +16,7 @@ using OpenRA.FileFormats;
|
||||
|
||||
namespace OpenRA.Network
|
||||
{
|
||||
class OrderManager : IDisposable
|
||||
public class OrderManager : IDisposable
|
||||
{
|
||||
readonly SyncReport syncReport;
|
||||
readonly FrameData frameData = new FrameData();
|
||||
@@ -47,7 +47,7 @@ namespace OpenRA.Network
|
||||
|
||||
NetFrameNumber = 1;
|
||||
for( int i = NetFrameNumber ; i <= FramesAhead ; i++ )
|
||||
Connection.Send( new List<Order>().Serialize( i ) );
|
||||
Connection.Send( i, new List<byte[]>() );
|
||||
}
|
||||
|
||||
public OrderManager( string host, int port, IConnection conn )
|
||||
@@ -73,7 +73,7 @@ namespace OpenRA.Network
|
||||
{
|
||||
var immediateOrders = localOrders.Where( o => o.IsImmediate ).ToList();
|
||||
if( immediateOrders.Count != 0 )
|
||||
Connection.Send( immediateOrders.Serialize( 0 ) );
|
||||
Connection.SendImmediate( immediateOrders.Select( o => o.Serialize() ).ToList() );
|
||||
localOrders.RemoveAll( o => o.IsImmediate );
|
||||
|
||||
var immediatePackets = new List<Pair<int, byte[]>>();
|
||||
@@ -99,7 +99,7 @@ namespace OpenRA.Network
|
||||
|
||||
Dictionary<int, byte[]> syncForFrame = new Dictionary<int, byte[]>();
|
||||
|
||||
void CheckSync(byte[] packet)
|
||||
void CheckSync( byte[] packet )
|
||||
{
|
||||
var frame = BitConverter.ToInt32(packet, 0);
|
||||
byte[] existingSync;
|
||||
@@ -156,7 +156,7 @@ namespace OpenRA.Network
|
||||
if( !IsReadyForNextFrame )
|
||||
throw new InvalidOperationException();
|
||||
|
||||
Connection.Send( localOrders.Serialize( NetFrameNumber + FramesAhead ) );
|
||||
Connection.Send( NetFrameNumber + FramesAhead, localOrders.Select( o => o.Serialize() ).ToList() );
|
||||
localOrders.Clear();
|
||||
|
||||
var sync = new List<int>();
|
||||
@@ -168,13 +168,11 @@ namespace OpenRA.Network
|
||||
sync.Add( world.SyncHash() );
|
||||
}
|
||||
|
||||
var ss = sync.SerializeSync( NetFrameNumber );
|
||||
Connection.Send( ss );
|
||||
var ss = sync.SerializeSync();
|
||||
Connection.SendSync( NetFrameNumber, ss );
|
||||
|
||||
syncReport.UpdateSyncReport();
|
||||
|
||||
CheckSync( ss );
|
||||
|
||||
++NetFrameNumber;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,13 +26,26 @@ namespace OpenRA.Network
|
||||
get { return ConnectionState.Connected; }
|
||||
}
|
||||
|
||||
public void Send( byte[] packet )
|
||||
// do nothing; ignore locally generated orders
|
||||
public void Send( int frame, List<byte[]> orders ) { }
|
||||
public void SendImmediate( List<byte[]> orders ) { }
|
||||
public void SendSync( int frame, byte[] syncData )
|
||||
{
|
||||
// do nothing; ignore locally generated orders
|
||||
var ms = new MemoryStream();
|
||||
ms.Write( BitConverter.GetBytes( frame ) );
|
||||
ms.Write( syncData );
|
||||
sync.Add( ms.ToArray() );
|
||||
}
|
||||
|
||||
List<byte[]> sync = new List<byte[]>();
|
||||
|
||||
public void Receive( Action<int, byte[]> packetFn )
|
||||
{
|
||||
while( sync.Count != 0 )
|
||||
{
|
||||
packetFn( LocalClientId, sync[ 0 ] );
|
||||
sync.RemoveAt( 0 );
|
||||
}
|
||||
if( replayStream == null ) return;
|
||||
|
||||
var reader = new BinaryReader( replayStream );
|
||||
@@ -52,23 +65,20 @@ namespace OpenRA.Network
|
||||
class ReplayRecorderConnection : IConnection
|
||||
{
|
||||
IConnection inner;
|
||||
FileStream replayFile;
|
||||
BinaryWriter writer;
|
||||
|
||||
public ReplayRecorderConnection( IConnection inner, FileStream replayFile )
|
||||
{
|
||||
this.inner = inner;
|
||||
this.replayFile = replayFile;
|
||||
this.writer = new BinaryWriter( replayFile );
|
||||
}
|
||||
|
||||
public int LocalClientId { get { return inner.LocalClientId; } }
|
||||
public ConnectionState ConnectionState { get { return inner.ConnectionState; } }
|
||||
|
||||
public void Send( byte[] packet )
|
||||
{
|
||||
inner.Send( packet );
|
||||
}
|
||||
public void Send( int frame, List<byte[]> orders ) { inner.Send( frame, orders ); }
|
||||
public void SendImmediate( List<byte[]> orders ) { inner.SendImmediate( orders ); }
|
||||
public void SendSync( int frame, byte[] syncData ) { inner.SendSync( frame, syncData ); }
|
||||
|
||||
public void Receive( Action<int, byte[]> packetFn )
|
||||
{
|
||||
|
||||
@@ -21,20 +21,21 @@ namespace OpenRA.Network
|
||||
public List<Slot> Slots = new List<Slot>();
|
||||
public Global GlobalSettings = new Global();
|
||||
|
||||
public Client ClientWithIndex( int clientID )
|
||||
public Client ClientWithIndex(int clientID)
|
||||
{
|
||||
return Clients.SingleOrDefault( c => c.Index == clientID );
|
||||
return Clients.SingleOrDefault(c => c.Index == clientID);
|
||||
}
|
||||
|
||||
public Client ClientInSlot( Slot slot )
|
||||
public Client ClientInSlot(Slot slot)
|
||||
{
|
||||
return Clients.SingleOrDefault( c => c.Slot == slot.Index );
|
||||
return Clients.SingleOrDefault(c => c.Slot == slot.Index);
|
||||
}
|
||||
|
||||
public enum ClientState
|
||||
{
|
||||
NotReady,
|
||||
Ready
|
||||
Ready,
|
||||
Disconnected = 1000
|
||||
}
|
||||
|
||||
public class Client
|
||||
@@ -55,8 +56,8 @@ namespace OpenRA.Network
|
||||
public int Index;
|
||||
public string Bot; // trait name of the bot to initialize in this slot, or null otherwise.
|
||||
public bool Closed; // host has explicitly closed this slot.
|
||||
public string MapPlayer; // playerReference to bind against.
|
||||
|
||||
public string MapPlayer; // playerReference to bind against.
|
||||
public bool Spectator = false; // Spectating or not
|
||||
// todo: more stuff?
|
||||
}
|
||||
|
||||
@@ -71,7 +72,7 @@ namespace OpenRA.Network
|
||||
public bool AllowCheats = false;
|
||||
}
|
||||
|
||||
public Session( string[] mods )
|
||||
public Session(string[] mods)
|
||||
{
|
||||
this.GlobalSettings.Mods = mods.ToArray();
|
||||
}
|
||||
@@ -80,27 +81,27 @@ namespace OpenRA.Network
|
||||
{
|
||||
var clientData = new List<MiniYamlNode>();
|
||||
|
||||
foreach( var client in Clients )
|
||||
clientData.Add( new MiniYamlNode( "Client@{0}".F( client.Index ), FieldSaver.Save( client ) ) );
|
||||
foreach (var client in Clients)
|
||||
clientData.Add(new MiniYamlNode("Client@{0}".F(client.Index), FieldSaver.Save(client)));
|
||||
|
||||
foreach( var slot in Slots )
|
||||
clientData.Add( new MiniYamlNode( "Slot@{0}".F( slot.Index ), FieldSaver.Save( slot ) ) );
|
||||
foreach (var slot in Slots)
|
||||
clientData.Add(new MiniYamlNode("Slot@{0}".F(slot.Index), FieldSaver.Save(slot)));
|
||||
|
||||
clientData.Add( new MiniYamlNode( "GlobalSettings", FieldSaver.Save( GlobalSettings ) ) );
|
||||
clientData.Add(new MiniYamlNode("GlobalSettings", FieldSaver.Save(GlobalSettings)));
|
||||
|
||||
return clientData.WriteToString();
|
||||
}
|
||||
|
||||
public static Session Deserialize(string data)
|
||||
{
|
||||
var session = new Session( Game.Settings.Game.Mods );
|
||||
var session = new Session(Game.Settings.Game.Mods);
|
||||
|
||||
var ys = MiniYaml.FromString(data);
|
||||
foreach (var y in ys)
|
||||
{
|
||||
var yy = y.Key.Split('@');
|
||||
|
||||
switch( yy[0] )
|
||||
switch (yy[0])
|
||||
{
|
||||
case "GlobalSettings":
|
||||
FieldLoader.Load(session.GlobalSettings, y.Value);
|
||||
@@ -111,7 +112,7 @@ namespace OpenRA.Network
|
||||
break;
|
||||
|
||||
case "Slot":
|
||||
session.Slots.Add(FieldLoader.Load<Session.Slot>(y.Value ));
|
||||
session.Slots.Add(FieldLoader.Load<Session.Slot>(y.Value));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Support;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Network
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#region Copyright & License Information
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
@@ -16,7 +16,7 @@ namespace OpenRA.Network
|
||||
{
|
||||
static class UnitOrders
|
||||
{
|
||||
static Player FindPlayerByClient( this World world, Session.Client c)
|
||||
static Player FindPlayerByClient(this World world, Session.Client c)
|
||||
{
|
||||
/* todo: this is still a hack.
|
||||
* the cases we're trying to avoid are the extra players on the host's client -- Neutral, other MapPlayers,
|
||||
@@ -25,106 +25,119 @@ namespace OpenRA.Network
|
||||
p => p.ClientIndex == c.Index && p.PlayerName == c.Name);
|
||||
}
|
||||
|
||||
public static void ProcessOrder( OrderManager orderManager, World world, int clientId, Order order )
|
||||
public static void ProcessOrder(OrderManager orderManager, World world, int clientId, Order order)
|
||||
{
|
||||
// Drop exploiting orders
|
||||
if (order.Subject != null && order.Subject.Owner.ClientIndex != clientId)
|
||||
if (world != null)
|
||||
{
|
||||
Game.Debug("Detected exploit order from {0}: {1}".F(clientId, order.OrderString));
|
||||
return;
|
||||
if (!world.WorldActor.TraitsImplementing<IValidateOrder>().All(vo =>
|
||||
vo.OrderValidation(orderManager, world, clientId, order)))
|
||||
return;
|
||||
}
|
||||
|
||||
switch( order.OrderString )
|
||||
|
||||
switch (order.OrderString)
|
||||
{
|
||||
case "Chat":
|
||||
{
|
||||
var client = orderManager.LobbyInfo.ClientWithIndex( clientId );
|
||||
if (client != null)
|
||||
{
|
||||
var player = world != null ? world.FindPlayerByClient(client) : null;
|
||||
var suffix = (player != null && player.WinState == WinState.Lost) ? " (Dead)" : "";
|
||||
Game.AddChatLine(client.Color1, client.Name, order.TargetString);
|
||||
}
|
||||
else
|
||||
Game.AddChatLine(Color.White, "(player {0})".F(clientId), order.TargetString);
|
||||
break;
|
||||
}
|
||||
case "TeamChat":
|
||||
{
|
||||
var client = orderManager.LobbyInfo.ClientWithIndex(clientId);
|
||||
if (client != null)
|
||||
{
|
||||
if (world == null)
|
||||
var client = orderManager.LobbyInfo.ClientWithIndex(clientId);
|
||||
if (client != null)
|
||||
{
|
||||
if (client.Team == orderManager.LocalClient.Team)
|
||||
Game.AddChatLine(client.Color1, client.Name + " (Team)",
|
||||
order.TargetString);
|
||||
var player = world != null ? world.FindPlayerByClient(client) : null;
|
||||
var suffix = (player != null && player.WinState == WinState.Lost) ? " (Dead)" : "";
|
||||
Game.AddChatLine(client.Color1, client.Name + suffix, order.TargetString);
|
||||
}
|
||||
else
|
||||
Game.AddChatLine(Color.White, "(player {0})".F(clientId), order.TargetString);
|
||||
break;
|
||||
}
|
||||
case "Disconnected": /* reports that the target player disconnected */
|
||||
{
|
||||
var client = orderManager.LobbyInfo.ClientWithIndex(clientId);
|
||||
if (client != null)
|
||||
{
|
||||
var player = world.FindPlayerByClient(client);
|
||||
var display = player != null
|
||||
&& (world.LocalPlayer != null && player.Stances[world.LocalPlayer] == Stance.Ally
|
||||
|| player.WinState == WinState.Lost);
|
||||
client.State = Session.ClientState.Disconnected;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "TeamChat":
|
||||
{
|
||||
var client = orderManager.LobbyInfo.ClientWithIndex(clientId);
|
||||
|
||||
if (display)
|
||||
if (client != null)
|
||||
{
|
||||
if (world == null)
|
||||
{
|
||||
var suffix = (player != null && player.WinState == WinState.Lost) ? " (Dead)" : " (Team)";
|
||||
Game.AddChatLine(client.Color1, client.Name + suffix, order.TargetString);
|
||||
if (client.Team == orderManager.LocalClient.Team)
|
||||
Game.AddChatLine(client.Color1, client.Name + " (Team)",
|
||||
order.TargetString);
|
||||
}
|
||||
else
|
||||
{
|
||||
var player = world.FindPlayerByClient(client);
|
||||
var display = player != null
|
||||
&&
|
||||
(world.LocalPlayer != null &&
|
||||
player.Stances[world.LocalPlayer] == Stance.Ally
|
||||
|| player.WinState == WinState.Lost);
|
||||
|
||||
if (display)
|
||||
{
|
||||
var suffix = (player != null && player.WinState == WinState.Lost)
|
||||
? " (Dead)"
|
||||
: " (Team)";
|
||||
Game.AddChatLine(client.Color1, client.Name + suffix, order.TargetString);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "StartGame":
|
||||
{
|
||||
Game.AddChatLine(Color.White, "Server", "The game has started.");
|
||||
Game.StartGame(orderManager.LobbyInfo.GlobalSettings.Map);
|
||||
break;
|
||||
}
|
||||
case "SyncInfo":
|
||||
{
|
||||
orderManager.LobbyInfo = Session.Deserialize( order.TargetString );
|
||||
|
||||
//if( !world.GameHasStarted )
|
||||
// world.SharedRandom = new XRandom( LobbyInfo.GlobalSettings.RandomSeed );
|
||||
|
||||
//if (orderManager.Connection.ConnectionState == ConnectionState.Connected)
|
||||
// world.SetLocalPlayer(orderManager.Connection.LocalClientId);
|
||||
|
||||
if( orderManager.FramesAhead != orderManager.LobbyInfo.GlobalSettings.OrderLatency
|
||||
&& !orderManager.GameStarted )
|
||||
case "StartGame":
|
||||
{
|
||||
orderManager.FramesAhead = orderManager.LobbyInfo.GlobalSettings.OrderLatency;
|
||||
Game.Debug( "Order lag is now {0} frames.".F( orderManager.LobbyInfo.GlobalSettings.OrderLatency ) );
|
||||
Game.AddChatLine(Color.White, "Server", "The game has started.");
|
||||
Game.StartGame(orderManager.LobbyInfo.GlobalSettings.Map);
|
||||
break;
|
||||
}
|
||||
case "SyncInfo":
|
||||
{
|
||||
orderManager.LobbyInfo = Session.Deserialize(order.TargetString);
|
||||
|
||||
if (orderManager.FramesAhead != orderManager.LobbyInfo.GlobalSettings.OrderLatency
|
||||
&& !orderManager.GameStarted)
|
||||
{
|
||||
orderManager.FramesAhead = orderManager.LobbyInfo.GlobalSettings.OrderLatency;
|
||||
Game.Debug(
|
||||
"Order lag is now {0} frames.".F(orderManager.LobbyInfo.GlobalSettings.OrderLatency));
|
||||
}
|
||||
Game.SyncLobbyInfo();
|
||||
break;
|
||||
}
|
||||
|
||||
Game.SyncLobbyInfo();
|
||||
break;
|
||||
}
|
||||
case "SetStance":
|
||||
{
|
||||
var targetPlayer = order.Player.World.players[order.TargetLocation.X];
|
||||
var oldStance = order.Player.Stances[targetPlayer];
|
||||
var newStance = (Stance)order.TargetLocation.Y;
|
||||
case "SetStance":
|
||||
{
|
||||
var targetPlayer = order.Player.World.players[order.TargetLocation.X];
|
||||
var newStance = (Stance)order.TargetLocation.Y;
|
||||
|
||||
SetPlayerStance(world, order.Player, targetPlayer, newStance);
|
||||
SetPlayerStance(world, order.Player, targetPlayer, newStance);
|
||||
|
||||
// automatically declare war reciprocally
|
||||
if (newStance == Stance.Enemy)
|
||||
SetPlayerStance(world, targetPlayer, order.Player, newStance);
|
||||
// automatically declare war reciprocally
|
||||
if (newStance == Stance.Enemy)
|
||||
SetPlayerStance(world, targetPlayer, order.Player, newStance);
|
||||
|
||||
Game.Debug("{0} has set diplomatic stance vs {1} to {2}".F(
|
||||
order.Player.PlayerName, targetPlayer.PlayerName, newStance));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
if( !order.IsImmediate )
|
||||
foreach (var t in order.Subject.TraitsImplementing<IResolveOrder>())
|
||||
t.ResolveOrder(order.Subject, order);
|
||||
break;
|
||||
}
|
||||
Game.Debug("{0} has set diplomatic stance vs {1} to {2}".F(
|
||||
order.Player.PlayerName, targetPlayer.PlayerName, newStance));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
if( !order.IsImmediate )
|
||||
{
|
||||
var self = order.Subject;
|
||||
var health = self.TraitOrDefault<Health>();
|
||||
if( health == null || !health.IsDead )
|
||||
foreach( var t in self.TraitsImplementing<IResolveOrder>() )
|
||||
t.ResolveOrder( self, order );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,19 @@
|
||||
using System;
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using OpenRA.FileFormats;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
|
||||
@@ -79,7 +79,6 @@
|
||||
<Compile Include="Group.cs" />
|
||||
<Compile Include="Orders\GenericSelectTarget.cs" />
|
||||
<Compile Include="Server\ProtocolVersion.cs" />
|
||||
<Compile Include="Traits\BaseBuilding.cs" />
|
||||
<Compile Include="Traits\LintAttributes.cs" />
|
||||
<Compile Include="Traits\Player\PlayerResources.cs" />
|
||||
<Compile Include="Traits\World\Shroud.cs" />
|
||||
@@ -106,7 +105,6 @@
|
||||
<Compile Include="Network\Connection.cs" />
|
||||
<Compile Include="Network\OrderIO.cs" />
|
||||
<Compile Include="Network\OrderManager.cs" />
|
||||
<Compile Include="PathSearch.cs" />
|
||||
<Compile Include="Selection.cs" />
|
||||
<Compile Include="Server\Connection.cs" />
|
||||
<Compile Include="Server\Exts.cs" />
|
||||
@@ -117,12 +115,10 @@
|
||||
<Compile Include="Sound.cs" />
|
||||
<Compile Include="Support\PerfHistory.cs" />
|
||||
<Compile Include="Sync.cs" />
|
||||
<Compile Include="Traits\CustomSellValue.cs" />
|
||||
<Compile Include="Traits\World\SpatialBins.cs" />
|
||||
<Compile Include="Traits\World\Country.cs" />
|
||||
<Compile Include="Actor.cs" />
|
||||
<Compile Include="Cursor.cs" />
|
||||
<Compile Include="GameRules\Footprint.cs" />
|
||||
<Compile Include="GameRules\Rules.cs" />
|
||||
<Compile Include="Graphics\Animation.cs" />
|
||||
<Compile Include="Game.cs" />
|
||||
@@ -131,19 +127,14 @@
|
||||
<Compile Include="Graphics\LineRenderer.cs" />
|
||||
<Compile Include="Graphics\WorldRenderer.cs" />
|
||||
<Compile Include="Traits\Activities\Idle.cs" />
|
||||
<Compile Include="Traits\Activities\RemoveSelf.cs" />
|
||||
<Compile Include="Traits\Activities\Sell.cs" />
|
||||
<Compile Include="Orders\IOrderGenerator.cs" />
|
||||
<Compile Include="Player.cs" />
|
||||
<Compile Include="Graphics\Sheet.cs" />
|
||||
<Compile Include="PathFinder.cs" />
|
||||
<Compile Include="Graphics\Sequence.cs" />
|
||||
<Compile Include="Network\Order.cs" />
|
||||
<Compile Include="Graphics\SequenceProvider.cs" />
|
||||
<Compile Include="Graphics\SheetBuilder.cs" />
|
||||
<Compile Include="Graphics\HardwarePalette.cs" />
|
||||
<Compile Include="MainWindow.cs">
|
||||
</Compile>
|
||||
<Compile Include="Support\Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Graphics\Renderer.cs" />
|
||||
@@ -151,15 +142,10 @@
|
||||
<Compile Include="Graphics\SpriteRenderer.cs" />
|
||||
<Compile Include="Graphics\SpriteSheetBuilder.cs" />
|
||||
<Compile Include="Graphics\TerrainRenderer.cs" />
|
||||
<Compile Include="Traits\Activities\Move.cs" />
|
||||
<Compile Include="Traits\Activities\Turn.cs" />
|
||||
<Compile Include="Traits\Building.cs" />
|
||||
<Compile Include="Traits\World\BuildingInfluence.cs" />
|
||||
<Compile Include="Traits\World\PlayerColorPalette.cs" />
|
||||
<Compile Include="Traits\World\ResourceLayer.cs" />
|
||||
<Compile Include="Traits\World\ResourceType.cs" />
|
||||
<Compile Include="Traits\Selectable.cs" />
|
||||
<Compile Include="Traits\Mobile.cs" />
|
||||
<Compile Include="Traits\Render\RenderSimple.cs" />
|
||||
<Compile Include="Traits\TraitsInterfaces.cs" />
|
||||
<Compile Include="Traits\World\UnitInfluence.cs" />
|
||||
@@ -169,12 +155,10 @@
|
||||
<Compile Include="Graphics\Util.cs" />
|
||||
<Compile Include="Graphics\Viewport.cs" />
|
||||
<Compile Include="Orders\UnitOrderGenerator.cs" />
|
||||
<Compile Include="Widgets\WorldTooltipWidget.cs" />
|
||||
<Compile Include="World.cs" />
|
||||
<Compile Include="WorldUtils.cs" />
|
||||
<Compile Include="Traits\Player\EvaAlerts.cs" />
|
||||
<Compile Include="Traits\World\ScreenShaker.cs" />
|
||||
<Compile Include="Traits\LineBuild.cs" />
|
||||
<Compile Include="Widgets\WidgetLoader.cs" />
|
||||
<Compile Include="Widgets\ButtonWidget.cs" />
|
||||
<Compile Include="Widgets\Widget.cs" />
|
||||
@@ -200,9 +184,7 @@
|
||||
<Compile Include="Widgets\ViewportScrollControllerWidget.cs" />
|
||||
<Compile Include="Traits\Player\DeveloperMode.cs" />
|
||||
<Compile Include="Traits\RevealsShroud.cs" />
|
||||
<Compile Include="Traits\Targetable.cs" />
|
||||
<Compile Include="Traits\Health.cs" />
|
||||
<Compile Include="Traits\Activities\Drag.cs" />
|
||||
<Compile Include="Widgets\VqaPlayerWidget.cs" />
|
||||
<Compile Include="Widgets\Delegates\VideoPlayerDelegate.cs" />
|
||||
<Compile Include="GameRules\Settings.cs" />
|
||||
@@ -210,8 +192,7 @@
|
||||
<Compile Include="Traits\ActorStance.cs" />
|
||||
<Compile Include="Traits\Armor.cs" />
|
||||
<Compile Include="Graphics\CursorProvider.cs" />
|
||||
<Compile Include="Traits\Player\TechTree.cs" />
|
||||
<Compile Include="Traits\Player\PowerManager.cs" />
|
||||
<Compile Include="Server\TraitInterfaces.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">
|
||||
@@ -220,6 +201,7 @@
|
||||
</ProjectReference>
|
||||
<Compile Include="ActorInitializer.cs" />
|
||||
<Compile Include="ActorReference.cs" />
|
||||
<Compile Include="InputHandler.cs" />
|
||||
<Compile Include="ModData.cs" />
|
||||
<Compile Include="Map.cs" />
|
||||
<Compile Include="Network\FrameData.cs" />
|
||||
@@ -227,10 +209,13 @@
|
||||
<Compile Include="Network\Session.cs" />
|
||||
<Compile Include="ObjectCreator.cs" />
|
||||
<Compile Include="Network\SyncReport.cs" />
|
||||
<Compile Include="Traits\EditorAppearance.cs" />
|
||||
<Compile Include="Traits\ValidateOrder.cs" />
|
||||
<Compile Include="Traits\Scale.cs" />
|
||||
<Compile Include="TraitDictionary.cs" />
|
||||
<Compile Include="Traits\Activities\CancelableActivity.cs" />
|
||||
<Compile Include="Traits\SharesCell.cs" />
|
||||
<Compile Include="Traits\Valued.cs" />
|
||||
<Compile Include="Traits\World\BibLayer.cs" />
|
||||
<Compile Include="Widgets\PasswordFieldWidget.cs" />
|
||||
<Compile Include="Widgets\Delegates\DeveloperModeDelegate.cs" />
|
||||
<Compile Include="Widgets\ScrollingTextWidget.cs" />
|
||||
</ItemGroup>
|
||||
@@ -254,6 +239,9 @@
|
||||
<ItemGroup>
|
||||
<Content Include="OpenRA.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="ServerTraits\" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
|
||||
@@ -20,35 +20,48 @@ namespace OpenRA.Orders
|
||||
readonly IEnumerable<Actor> subjects;
|
||||
readonly string order;
|
||||
readonly string cursor;
|
||||
readonly MouseButton expectedButton;
|
||||
|
||||
public GenericSelectTarget(IEnumerable<Actor> subjects, string order, string cursor)
|
||||
public GenericSelectTarget(IEnumerable<Actor> subjects, string order, string cursor, MouseButton button)
|
||||
{
|
||||
this.subjects = subjects;
|
||||
this.order = order;
|
||||
this.cursor = cursor;
|
||||
expectedButton = button;
|
||||
}
|
||||
|
||||
public GenericSelectTarget(IEnumerable<Actor> subjects, string order, string cursor)
|
||||
: this(subjects, order, cursor, MouseButton.Left)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public GenericSelectTarget(Actor subject, string order, string cursor)
|
||||
: this(new Actor[] { subject }, order, cursor)
|
||||
{
|
||||
this.subjects = new Actor[] { subject };
|
||||
this.order = order;
|
||||
this.cursor = cursor;
|
||||
|
||||
}
|
||||
|
||||
public GenericSelectTarget(Actor subject, string order, string cursor, MouseButton button)
|
||||
: this(new Actor[] { subject }, order, cursor, button)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public IEnumerable<Order> Order(World world, int2 xy, MouseInput mi)
|
||||
{
|
||||
if (mi.Button == MouseButton.Right)
|
||||
if (mi.Button != expectedButton)
|
||||
world.CancelInputMode();
|
||||
return OrderInner(world, xy, mi);
|
||||
}
|
||||
|
||||
IEnumerable<Order> OrderInner(World world, int2 xy, MouseInput mi)
|
||||
{
|
||||
if (mi.Button == MouseButton.Left && world.Map.IsInMap(xy))
|
||||
if (mi.Button == expectedButton && world.Map.IsInMap(xy))
|
||||
{
|
||||
world.CancelInputMode();
|
||||
foreach (var subject in subjects)
|
||||
yield return new Order(order, subject, xy);
|
||||
yield return new Order(order, subject, xy, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,6 +97,9 @@ namespace OpenRA.Orders
|
||||
public GenericSelectTargetWithBuilding(Actor subject, string order, string cursor)
|
||||
: base(subject, order, cursor) { }
|
||||
|
||||
public GenericSelectTargetWithBuilding(Actor subject, string order, string cursor, MouseButton button)
|
||||
: base(subject, order, cursor, button) { }
|
||||
|
||||
public override void Tick(World world)
|
||||
{
|
||||
var hasStructure = world.Queries.OwnedBy[world.LocalPlayer]
|
||||
|
||||
@@ -17,31 +17,61 @@ namespace OpenRA.Orders
|
||||
{
|
||||
class UnitOrderGenerator : IOrderGenerator
|
||||
{
|
||||
public IEnumerable<Order> Order( World world, int2 xy, MouseInput mi )
|
||||
{
|
||||
var underCursor = world.FindUnitsAtMouse(mi.Location)
|
||||
.Where(a => a.Info.Traits.Contains<TargetableInfo>())
|
||||
.OrderByDescending(a => a.Info.Traits.Contains<SelectableInfo>() ? a.Info.Traits.Get<SelectableInfo>().Priority : int.MinValue)
|
||||
.FirstOrDefault();
|
||||
|
||||
var orders = world.Selection.Actors
|
||||
.Select(a => OrderForUnit(a, xy, mi, underCursor))
|
||||
.Where(o => o != null)
|
||||
.ToArray();
|
||||
|
||||
var actorsInvolved = orders.Select(o => o.self).Distinct();
|
||||
if (actorsInvolved.Any())
|
||||
yield return new Order("CreateGroup", actorsInvolved.First().Owner.PlayerActor,
|
||||
string.Join(",", actorsInvolved.Select(a => a.ActorID.ToString()).ToArray()));
|
||||
public IEnumerable<Order> Order( World world, int2 xy, MouseInput mi )
|
||||
{
|
||||
var custom = world.WorldActor.TraitOrDefault<ICustomUnitOrderGenerator>();
|
||||
if (custom != null)
|
||||
{
|
||||
var customOrders = custom.Order(world, xy, mi);
|
||||
|
||||
foreach( var o in orders )
|
||||
yield return CheckSameOrder( o.iot, o.trait.IssueOrder( o.self, o.iot, o.target ) );
|
||||
foreach (var o in customOrders)
|
||||
yield return o;
|
||||
}
|
||||
else
|
||||
{
|
||||
var underCursor = world.FindUnitsAtMouse(mi.Location)
|
||||
.Where(a => a.HasTrait<ITargetable>())
|
||||
.OrderByDescending(
|
||||
a =>
|
||||
a.Info.Traits.Contains<SelectableInfo>()
|
||||
? a.Info.Traits.Get<SelectableInfo>().Priority
|
||||
: int.MinValue)
|
||||
.FirstOrDefault();
|
||||
|
||||
var orders = world.Selection.Actors
|
||||
.Select(a => OrderForUnit(a, xy, mi, underCursor))
|
||||
.Where(o => o != null)
|
||||
.ToArray();
|
||||
|
||||
var actorsInvolved = orders.Select(o => o.self).Distinct();
|
||||
if (actorsInvolved.Any())
|
||||
yield return new Order("CreateGroup", actorsInvolved.First().Owner.PlayerActor,
|
||||
string.Join(",", actorsInvolved.Select(a => a.ActorID.ToString()).ToArray()), false)
|
||||
;
|
||||
|
||||
foreach (var o in orders)
|
||||
yield return CheckSameOrder(o.iot, o.trait.IssueOrder(o.self, o.iot, o.target, mi.Modifiers.HasModifier(Modifiers.Shift)));
|
||||
}
|
||||
}
|
||||
|
||||
public void Tick( World world ) {}
|
||||
public void Tick( World world )
|
||||
{
|
||||
var custom = world.WorldActor.TraitOrDefault<ICustomUnitOrderGenerator>();
|
||||
if (custom != null)
|
||||
{
|
||||
custom.Tick(world);
|
||||
}
|
||||
}
|
||||
|
||||
public void RenderBeforeWorld( WorldRenderer wr, World world )
|
||||
{
|
||||
var custom = world.WorldActor.TraitOrDefault<ICustomUnitOrderGenerator>();
|
||||
if (custom != null)
|
||||
{
|
||||
custom.RenderBeforeWorld(wr, world);
|
||||
return;
|
||||
}
|
||||
|
||||
public void RenderBeforeWorld( WorldRenderer wr, World world )
|
||||
{
|
||||
foreach (var a in world.Selection.Actors)
|
||||
if (!a.Destroyed)
|
||||
foreach (var t in a.TraitsImplementing<IPreRenderSelection>())
|
||||
@@ -50,8 +80,15 @@ namespace OpenRA.Orders
|
||||
Game.Renderer.Flush();
|
||||
}
|
||||
|
||||
public void RenderAfterWorld( WorldRenderer wr, World world )
|
||||
{
|
||||
public void RenderAfterWorld( WorldRenderer wr, World world )
|
||||
{
|
||||
var custom = world.WorldActor.TraitOrDefault<ICustomUnitOrderGenerator>();
|
||||
if (custom != null)
|
||||
{
|
||||
custom.RenderAfterWorld(wr, world);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var a in world.Selection.Actors)
|
||||
if (!a.Destroyed)
|
||||
foreach (var t in a.TraitsImplementing<IPostRenderSelection>())
|
||||
@@ -60,25 +97,34 @@ namespace OpenRA.Orders
|
||||
Game.Renderer.Flush();
|
||||
}
|
||||
|
||||
public string GetCursor( World world, int2 xy, MouseInput mi )
|
||||
{
|
||||
public string GetCursor( World world, int2 xy, MouseInput mi )
|
||||
{
|
||||
bool useSelect = false;
|
||||
|
||||
var custom = world.WorldActor.TraitOrDefault<ICustomUnitOrderGenerator>();
|
||||
if (custom != null)
|
||||
{
|
||||
return custom.GetCursor(world, xy, mi);
|
||||
}
|
||||
|
||||
var underCursor = world.FindUnitsAtMouse(mi.Location)
|
||||
.Where(a => a.Info.Traits.Contains<TargetableInfo>())
|
||||
.Where(a => a.HasTrait<ITargetable>())
|
||||
.OrderByDescending(a => a.Info.Traits.Contains<SelectableInfo>() ? a.Info.Traits.Get<SelectableInfo>().Priority : int.MinValue)
|
||||
.FirstOrDefault();
|
||||
|
||||
if( mi.Modifiers.HasModifier( Modifiers.Shift ) || !world.Selection.Actors.Any() )
|
||||
if( underCursor != null )
|
||||
return "select";
|
||||
|
||||
.FirstOrDefault();
|
||||
|
||||
|
||||
if (mi.Modifiers.HasModifier(Modifiers.Shift) || !world.Selection.Actors.Any())
|
||||
if (underCursor != null)
|
||||
useSelect = true;
|
||||
|
||||
var orders = world.Selection.Actors
|
||||
.Select(a => OrderForUnit(a, xy, mi, underCursor))
|
||||
.Where(o => o != null)
|
||||
.ToArray();
|
||||
|
||||
if( orders.Length == 0 ) return "default";
|
||||
if( orders.Length == 0 ) return (useSelect) ? "select" : "default";
|
||||
|
||||
return orders[ 0 ].cursor ?? "default";
|
||||
return orders[0].cursor ?? ((useSelect) ? "select" : "default");
|
||||
}
|
||||
|
||||
static UnitOrderResult OrderForUnit( Actor self, int2 xy, MouseInput mi, Actor underCursor )
|
||||
@@ -111,9 +157,9 @@ namespace OpenRA.Orders
|
||||
|
||||
string cursor = null;
|
||||
if( underCursor != null )
|
||||
if( o.Order.CanTargetUnit( self, underCursor, mi.Modifiers.HasModifier( Modifiers.Ctrl ), mi.Modifiers.HasModifier( Modifiers.Alt ), ref cursor ) )
|
||||
if (o.Order.CanTargetUnit(self, underCursor, mi.Modifiers.HasModifier(Modifiers.Ctrl), mi.Modifiers.HasModifier(Modifiers.Alt), mi.Modifiers.HasModifier(Modifiers.Shift), ref cursor))
|
||||
return new UnitOrderResult( self, o.Order, o.Trait, cursor, Target.FromActor( underCursor ) );
|
||||
if( o.Order.CanTargetLocation( self, xy, actorsAt, mi.Modifiers.HasModifier( Modifiers.Ctrl ), mi.Modifiers.HasModifier( Modifiers.Alt ), ref cursor ) )
|
||||
if (o.Order.CanTargetLocation(self, xy, actorsAt, mi.Modifiers.HasModifier(Modifiers.Ctrl), mi.Modifiers.HasModifier(Modifiers.Alt), mi.Modifiers.HasModifier(Modifiers.Shift), ref cursor))
|
||||
return new UnitOrderResult( self, o.Order, o.Trait, cursor, Target.FromCell( xy ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,85 +13,86 @@ using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Network;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
public enum PowerState { Normal, Low, Critical };
|
||||
public enum WinState { Won, Lost, Undefined };
|
||||
|
||||
public class Player
|
||||
{
|
||||
public Actor PlayerActor;
|
||||
public int Kills;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
public enum PowerState { Normal, Low, Critical };
|
||||
public enum WinState { Won, Lost, Undefined };
|
||||
|
||||
public class Player
|
||||
{
|
||||
public Actor PlayerActor;
|
||||
public int Kills;
|
||||
public int Deaths;
|
||||
public WinState WinState = WinState.Undefined;
|
||||
|
||||
public readonly string Palette;
|
||||
public readonly Color Color;
|
||||
public readonly Color Color2;
|
||||
|
||||
public readonly string PlayerName;
|
||||
public readonly string InternalName;
|
||||
public readonly CountryInfo Country;
|
||||
public readonly int Index;
|
||||
public WinState WinState = WinState.Undefined;
|
||||
|
||||
public readonly string Palette;
|
||||
public readonly Color Color;
|
||||
public readonly Color Color2;
|
||||
|
||||
public readonly string PlayerName;
|
||||
public readonly string InternalName;
|
||||
public readonly CountryInfo Country;
|
||||
public readonly int Index;
|
||||
public readonly bool NonCombatant = false;
|
||||
public readonly int ClientIndex;
|
||||
public readonly PlayerReference PlayerRef;
|
||||
public bool IsBot;
|
||||
|
||||
public ShroudRenderer Shroud;
|
||||
public World World { get; private set; }
|
||||
|
||||
public Player( World world, PlayerReference pr, int index )
|
||||
{
|
||||
World = world;
|
||||
Shroud = new ShroudRenderer(this, world.Map);
|
||||
|
||||
Index = index;
|
||||
Palette = "player"+index;
|
||||
|
||||
Color = pr.Color;
|
||||
public bool IsBot;
|
||||
|
||||
public ShroudRenderer Shroud;
|
||||
public World World { get; private set; }
|
||||
|
||||
public Player(World world, PlayerReference pr, int index)
|
||||
{
|
||||
World = world;
|
||||
Shroud = new ShroudRenderer(this, world.Map);
|
||||
|
||||
Index = index;
|
||||
Palette = "player" + index;
|
||||
|
||||
Color = pr.Color;
|
||||
Color2 = pr.Color2;
|
||||
ClientIndex = 0; /* it's a map player, "owned" by host */
|
||||
|
||||
PlayerName = InternalName = pr.Name;
|
||||
NonCombatant = pr.NonCombatant;
|
||||
Country = world.GetCountries()
|
||||
ClientIndex = 0; /* it's a map player, "owned" by host */
|
||||
|
||||
PlayerName = InternalName = pr.Name;
|
||||
NonCombatant = pr.NonCombatant;
|
||||
Country = world.GetCountries()
|
||||
.FirstOrDefault(c => pr.Race == c.Race)
|
||||
?? world.GetCountries().Random(world.SharedRandom);
|
||||
|
||||
PlayerRef = pr;
|
||||
|
||||
PlayerActor = world.CreateActor("Player", new TypeDictionary{ new OwnerInit( this ) });
|
||||
}
|
||||
|
||||
public Player( World world, Session.Client client, PlayerReference pr, int index )
|
||||
{
|
||||
World = world;
|
||||
Shroud = new ShroudRenderer(this, world.Map);
|
||||
|
||||
PlayerRef = pr;
|
||||
|
||||
PlayerActor = world.CreateActor("Player", new TypeDictionary { new OwnerInit(this) });
|
||||
}
|
||||
|
||||
public Player(World world, Session.Client client, PlayerReference pr, int index)
|
||||
{
|
||||
World = world;
|
||||
Shroud = new ShroudRenderer(this, world.Map);
|
||||
|
||||
Index = index;
|
||||
Palette = "player"+index;
|
||||
Color = client.Color1;
|
||||
Color2 = client.Color2;
|
||||
Palette = "player" + index;
|
||||
Color = client.Color1;
|
||||
Color2 = client.Color2;
|
||||
PlayerName = client.Name;
|
||||
InternalName = pr.Name;
|
||||
Country = world.GetCountries()
|
||||
.FirstOrDefault(c => client != null && client.Country == c.Race)
|
||||
|
||||
InternalName = pr.Name;
|
||||
Country = world.GetCountries()
|
||||
.FirstOrDefault(c => client != null && client.Country == c.Race)
|
||||
?? world.GetCountries().Random(world.SharedRandom);
|
||||
|
||||
ClientIndex = client.Index;
|
||||
PlayerRef = pr;
|
||||
|
||||
PlayerActor = world.CreateActor("Player", new TypeDictionary{ new OwnerInit( this ) });
|
||||
}
|
||||
|
||||
public void GiveAdvice(string advice)
|
||||
{
|
||||
Sound.PlayToPlayer(this, advice);
|
||||
}
|
||||
|
||||
public Dictionary<Player, Stance> Stances = new Dictionary<Player, Stance>();
|
||||
}
|
||||
PlayerRef = pr;
|
||||
|
||||
PlayerActor = world.CreateActor("Player", new TypeDictionary { new OwnerInit(this) });
|
||||
}
|
||||
|
||||
public void GiveAdvice(string advice)
|
||||
{
|
||||
Sound.PlayToPlayer(this, advice);
|
||||
}
|
||||
|
||||
public Dictionary<Player, Stance> Stances = new Dictionary<Player, Stance>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ using System.Net.Sockets;
|
||||
|
||||
namespace OpenRA.Server
|
||||
{
|
||||
class Connection
|
||||
public class Connection
|
||||
{
|
||||
public Socket socket;
|
||||
public List<byte> data = new List<byte>();
|
||||
@@ -35,7 +35,7 @@ namespace OpenRA.Server
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
bool ReadDataInner()
|
||||
bool ReadDataInner( Server server )
|
||||
{
|
||||
var rx = new byte[1024];
|
||||
var len = 0;
|
||||
@@ -49,7 +49,7 @@ namespace OpenRA.Server
|
||||
else
|
||||
{
|
||||
if (len == 0)
|
||||
Server.DropClient(this, null);
|
||||
server.DropClient(this, null);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace OpenRA.Server
|
||||
catch (SocketException e)
|
||||
{
|
||||
if (e.SocketErrorCode == SocketError.WouldBlock) break;
|
||||
Server.DropClient(this, e);
|
||||
server.DropClient(this, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -65,9 +65,9 @@ namespace OpenRA.Server
|
||||
return true;
|
||||
}
|
||||
|
||||
public void ReadData()
|
||||
public void ReadData( Server server )
|
||||
{
|
||||
if (ReadDataInner())
|
||||
if (ReadDataInner(server))
|
||||
while (data.Count >= ExpectLength)
|
||||
{
|
||||
var bytes = PopBytes(ExpectLength);
|
||||
@@ -82,16 +82,16 @@ namespace OpenRA.Server
|
||||
|
||||
case ReceiveState.Data:
|
||||
{
|
||||
Server.DispatchOrders(this, Frame, bytes);
|
||||
server.DispatchOrders(this, Frame, bytes);
|
||||
MostRecentFrame = Frame;
|
||||
ExpectLength = 8;
|
||||
State = ReceiveState.Header;
|
||||
|
||||
Server.UpdateInFlightFrames(this);
|
||||
server.UpdateInFlightFrames(this);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
||||
enum ReceiveState { Header, Data };
|
||||
public enum ReceiveState { Header, Data };
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA.Server
|
||||
{
|
||||
static class MasterServerQuery
|
||||
public static class MasterServerQuery
|
||||
{
|
||||
public static event Action<GameServer[]> OnComplete = _ => { };
|
||||
public static event Action<string> OnVersion = _ => { };
|
||||
@@ -62,8 +62,13 @@ namespace OpenRA.Server
|
||||
{
|
||||
try
|
||||
{
|
||||
motd.SetText(GetData(new Uri(masterServerUrl + "motd.php?v=" + ClientVersion)));
|
||||
motd.ResetScroll();
|
||||
string motdText = GetData(new Uri(masterServerUrl + "motd.php?v=" + ClientVersion));
|
||||
string[] p = motdText.Split('|');
|
||||
if (p.Length == 2 && p[1].Length == int.Parse(p[0]))
|
||||
{
|
||||
motd.SetText(p[1]);
|
||||
motd.ResetScroll();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -109,7 +114,7 @@ namespace OpenRA.Server
|
||||
}
|
||||
}
|
||||
|
||||
class GameServer
|
||||
public class GameServer
|
||||
{
|
||||
public readonly int Id = 0;
|
||||
public readonly string Name = null;
|
||||
|
||||
@@ -23,51 +23,54 @@ using OpenRA.Network;
|
||||
|
||||
namespace OpenRA.Server
|
||||
{
|
||||
static class Server
|
||||
public class Server
|
||||
{
|
||||
static List<Connection> conns = new List<Connection>();
|
||||
static TcpListener listener = null;
|
||||
static Dictionary<int, List<Connection>> inFlightFrames
|
||||
public List<Connection> conns = new List<Connection>();
|
||||
TcpListener listener = null;
|
||||
Dictionary<int, List<Connection>> inFlightFrames
|
||||
= new Dictionary<int, List<Connection>>();
|
||||
static Session lobbyInfo;
|
||||
static bool GameStarted = false;
|
||||
static string Name;
|
||||
static int ExternalPort;
|
||||
static int randomSeed;
|
||||
|
||||
TypeDictionary ServerTraits = new TypeDictionary();
|
||||
public Session lobbyInfo;
|
||||
public bool GameStarted = false;
|
||||
public string Name;
|
||||
int randomSeed;
|
||||
|
||||
const int DownloadChunkInterval = 20000;
|
||||
const int DownloadChunkSize = 16384;
|
||||
public ModData ModData;
|
||||
public Map Map;
|
||||
|
||||
const int MasterPingInterval = 60 * 3; // 3 minutes. server has a 5 minute TTL for games, so give ourselves a bit
|
||||
// of leeway.
|
||||
static int lastPing = 0;
|
||||
static bool isInternetServer;
|
||||
static string masterServerUrl;
|
||||
static bool isInitialPing;
|
||||
static ModData ModData;
|
||||
static Map Map;
|
||||
|
||||
public static void ServerMain(ModData modData, Settings settings, string map)
|
||||
public void Shutdown()
|
||||
{
|
||||
conns.Clear();
|
||||
GameStarted = false;
|
||||
foreach (var t in ServerTraits.WithInterface<INotifyServerShutdown>())
|
||||
t.ServerShutdown(this);
|
||||
|
||||
try { listener.Stop(); }
|
||||
catch { }
|
||||
}
|
||||
|
||||
public Server(ModData modData, Settings settings, string map)
|
||||
{
|
||||
Log.AddChannel("server", "server.log");
|
||||
|
||||
isInitialPing = true;
|
||||
Server.masterServerUrl = settings.Server.MasterServer;
|
||||
isInternetServer = settings.Server.AdvertiseOnline;
|
||||
listener = new TcpListener(IPAddress.Any, settings.Server.ListenPort);
|
||||
Name = settings.Server.Name;
|
||||
ExternalPort = settings.Server.ExternalPort;
|
||||
randomSeed = (int)DateTime.Now.ToBinary();
|
||||
ModData = modData;
|
||||
|
||||
foreach (var trait in modData.Manifest.ServerTraits)
|
||||
ServerTraits.Add( modData.ObjectCreator.CreateObject<ServerTrait>(trait) );
|
||||
|
||||
lobbyInfo = new Session( settings.Game.Mods );
|
||||
lobbyInfo.GlobalSettings.RandomSeed = randomSeed;
|
||||
lobbyInfo.GlobalSettings.Map = map;
|
||||
lobbyInfo.GlobalSettings.AllowCheats = settings.Server.AllowCheats;
|
||||
lobbyInfo.GlobalSettings.ServerName = settings.Server.Name;
|
||||
|
||||
LoadMap(); // populates the Session's slots, too.
|
||||
|
||||
foreach (var t in ServerTraits.WithInterface<INotifyServerStart>())
|
||||
t.ServerStarted(this);
|
||||
|
||||
Log.Write("server", "Initial mods: ");
|
||||
foreach( var m in lobbyInfo.GlobalSettings.Mods )
|
||||
Log.Write("server","- {0}", m);
|
||||
@@ -85,24 +88,21 @@ namespace OpenRA.Server
|
||||
|
||||
new Thread( _ =>
|
||||
{
|
||||
var timeout = ServerTraits.WithInterface<ITick>().Min(t => t.TickTimeout);
|
||||
for( ; ; )
|
||||
{
|
||||
var checkRead = new ArrayList();
|
||||
checkRead.Add( listener.Server );
|
||||
foreach( var c in conns ) checkRead.Add( c.socket );
|
||||
|
||||
Socket.Select( checkRead, null, null, MasterPingInterval * 10000 );
|
||||
Socket.Select( checkRead, null, null, timeout );
|
||||
|
||||
foreach( Socket s in checkRead )
|
||||
if( s == listener.Server ) AcceptConnection();
|
||||
else conns.Single( c => c.socket == s ).ReadData();
|
||||
else if (conns.Count > 0) conns.Single( c => c.socket == s ).ReadData( this );
|
||||
|
||||
if (Environment.TickCount - lastPing > MasterPingInterval * 1000)
|
||||
PingMasterServer();
|
||||
else
|
||||
lock (masterServerMessages)
|
||||
while (masterServerMessages.Count > 0)
|
||||
SendChat(null, masterServerMessages.Dequeue());
|
||||
foreach (var t in ServerTraits.WithInterface<ITick>())
|
||||
t.Tick(this);
|
||||
|
||||
if (conns.Count() == 0)
|
||||
{
|
||||
@@ -112,65 +112,38 @@ namespace OpenRA.Server
|
||||
}
|
||||
}
|
||||
} ) { IsBackground = true }.Start();
|
||||
|
||||
|
||||
}
|
||||
|
||||
static Session.Slot MakeSlotFromPlayerReference(PlayerReference pr)
|
||||
{
|
||||
if (!pr.Playable) return null;
|
||||
return new Session.Slot
|
||||
{
|
||||
MapPlayer = pr.Name,
|
||||
Bot = null, /* todo: allow the map to specify a bot class? */
|
||||
Closed = false,
|
||||
};
|
||||
}
|
||||
|
||||
static void LoadMap()
|
||||
{
|
||||
Map = new Map(ModData.AvailableMaps[lobbyInfo.GlobalSettings.Map].Package);
|
||||
lobbyInfo.Slots = Map.Players
|
||||
.Select(p => MakeSlotFromPlayerReference(p.Value))
|
||||
.Where(s => s != null)
|
||||
.Select((s, i) => { s.Index = i; return s; })
|
||||
.ToList();
|
||||
}
|
||||
|
||||
/* lobby rework todo:
|
||||
*
|
||||
* - auto-assign players to slots
|
||||
* - show all the slots in the lobby ui.
|
||||
* - rework the game start so we actually use the slots.
|
||||
* - all players should be able to click an empty slot to move to it
|
||||
* - host should be able to choose whether a slot is open/closed/bot, with
|
||||
* potentially more than one choice of bot class.
|
||||
* - host should be able to kick a client from the lobby by closing its slot.
|
||||
* - change lobby commands so the host can configure bots, rather than
|
||||
* just configuring itself.
|
||||
* - "teams together" option for team games -- will eliminate most need
|
||||
* for manual spawnpoint choosing.
|
||||
* - pick sensible non-conflicting colors for bots.
|
||||
* - 256 max players is a dirty hack
|
||||
*/
|
||||
|
||||
static int ChooseFreePlayerIndex()
|
||||
int ChooseFreePlayerIndex()
|
||||
{
|
||||
for (var i = 0; i < 8; i++)
|
||||
for (var i = 0; i < 256; i++)
|
||||
if (conns.All(c => c.PlayerIndex != i))
|
||||
return i;
|
||||
|
||||
throw new InvalidOperationException("Already got 8 players");
|
||||
throw new InvalidOperationException("Already got 256 players");
|
||||
}
|
||||
|
||||
static int ChooseFreeSlot()
|
||||
void AcceptConnection()
|
||||
{
|
||||
return lobbyInfo.Slots.First(s => !s.Closed && s.Bot == null
|
||||
&& !lobbyInfo.Clients.Any( c => c.Slot == s.Index )).Index;
|
||||
}
|
||||
Socket newSocket = null;
|
||||
|
||||
static void AcceptConnection()
|
||||
{
|
||||
var newConn = new Connection { socket = listener.AcceptSocket() };
|
||||
try
|
||||
{
|
||||
if (!listener.Server.IsBound) return;
|
||||
newSocket = listener.AcceptSocket();
|
||||
}catch
|
||||
{
|
||||
/* could have an exception here when listener 'goes away' when calling AcceptConnection! */
|
||||
/* alternative would be to use locking but the listener doesnt go away without a reason */
|
||||
return;
|
||||
}
|
||||
|
||||
var newConn = new Connection { socket = newSocket };
|
||||
try
|
||||
{
|
||||
if (GameStarted)
|
||||
@@ -190,32 +163,13 @@ namespace OpenRA.Server
|
||||
newConn.socket.Send(BitConverter.GetBytes(newConn.PlayerIndex));
|
||||
conns.Add(newConn);
|
||||
|
||||
var defaults = new GameRules.PlayerSettings();
|
||||
lobbyInfo.Clients.Add(
|
||||
new Session.Client()
|
||||
{
|
||||
Index = newConn.PlayerIndex,
|
||||
Color1 = defaults.Color1,
|
||||
Color2 = defaults.Color2,
|
||||
Name = defaults.Name,
|
||||
Country = "random",
|
||||
State = Session.ClientState.NotReady,
|
||||
SpawnPoint = 0,
|
||||
Team = 0,
|
||||
Slot = ChooseFreeSlot(),
|
||||
});
|
||||
|
||||
Log.Write("server", "Client {0}: Accepted connection from {1}",
|
||||
newConn.PlayerIndex, newConn.socket.RemoteEndPoint);
|
||||
|
||||
SendChat(newConn, "has joined the game.");
|
||||
|
||||
SyncLobbyInfo();
|
||||
foreach (var t in ServerTraits.WithInterface<IClientJoined>())
|
||||
t.ClientJoined(this, newConn);
|
||||
}
|
||||
catch (Exception e) { DropClient(newConn, e); }
|
||||
}
|
||||
|
||||
public static void UpdateInFlightFrames(Connection conn)
|
||||
public void UpdateInFlightFrames(Connection conn)
|
||||
{
|
||||
if (conn.Frame != 0)
|
||||
{
|
||||
@@ -231,7 +185,7 @@ namespace OpenRA.Server
|
||||
}
|
||||
}
|
||||
|
||||
static void DispatchOrdersToClient(Connection c, int client, int frame, byte[] data)
|
||||
void DispatchOrdersToClient(Connection c, int client, int frame, byte[] data)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -245,7 +199,7 @@ namespace OpenRA.Server
|
||||
catch( Exception e ) { DropClient( c, e ); }
|
||||
}
|
||||
|
||||
public static void DispatchOrders(Connection conn, int frame, byte[] data)
|
||||
public void DispatchOrders(Connection conn, int frame, byte[] data)
|
||||
{
|
||||
if (frame == 0 && conn != null)
|
||||
InterpretServerOrders(conn, data);
|
||||
@@ -257,7 +211,7 @@ namespace OpenRA.Server
|
||||
}
|
||||
}
|
||||
|
||||
static void InterpretServerOrders(Connection conn, byte[] data)
|
||||
void InterpretServerOrders(Connection conn, byte[] data)
|
||||
{
|
||||
var ms = new MemoryStream(data);
|
||||
var br = new BinaryReader(ms);
|
||||
@@ -274,294 +228,43 @@ namespace OpenRA.Server
|
||||
catch (EndOfStreamException) { }
|
||||
catch (NotImplementedException) { }
|
||||
}
|
||||
|
||||
static bool InterpretCommand(Connection conn, string cmd)
|
||||
{
|
||||
var dict = new Dictionary<string, Func<string, bool>>
|
||||
{
|
||||
{ "ready",
|
||||
s =>
|
||||
{
|
||||
// if we're downloading, we can't ready up.
|
||||
|
||||
var client = GetClient(conn);
|
||||
if (client.State == Session.ClientState.NotReady)
|
||||
client.State = Session.ClientState.Ready;
|
||||
else if (client.State == Session.ClientState.Ready)
|
||||
client.State = Session.ClientState.NotReady;
|
||||
|
||||
Log.Write("server", "Player @{0} is {1}",
|
||||
conn.socket.RemoteEndPoint, client.State);
|
||||
|
||||
SyncLobbyInfo();
|
||||
|
||||
if (conns.Count > 0 && conns.All(c => GetClient(c).State == Session.ClientState.Ready))
|
||||
InterpretCommand(conn, "startgame");
|
||||
|
||||
return true;
|
||||
}},
|
||||
{ "startgame",
|
||||
s =>
|
||||
{
|
||||
GameStarted = true;
|
||||
foreach( var c in conns )
|
||||
foreach( var d in conns )
|
||||
DispatchOrdersToClient( c, d.PlayerIndex, 0x7FFFFFFF, new byte[] { 0xBF } );
|
||||
|
||||
DispatchOrders(null, 0,
|
||||
new ServerOrder("StartGame", "").Serialize());
|
||||
|
||||
PingMasterServer();
|
||||
return true;
|
||||
}},
|
||||
{ "name",
|
||||
s =>
|
||||
{
|
||||
Log.Write("server", "Player@{0} is now known as {1}", conn.socket.RemoteEndPoint, s);
|
||||
GetClient(conn).Name = s;
|
||||
SyncLobbyInfo();
|
||||
return true;
|
||||
}},
|
||||
{ "lag",
|
||||
s =>
|
||||
{
|
||||
int lag;
|
||||
if (!int.TryParse(s, out lag)) { Log.Write("server", "Invalid order lag: {0}", s); return false; }
|
||||
|
||||
Log.Write("server", "Order lag is now {0} frames.", lag);
|
||||
|
||||
lobbyInfo.GlobalSettings.OrderLatency = lag;
|
||||
SyncLobbyInfo();
|
||||
return true;
|
||||
}},
|
||||
{ "race",
|
||||
s =>
|
||||
{
|
||||
GetClient(conn).Country = s;
|
||||
SyncLobbyInfo();
|
||||
return true;
|
||||
}},
|
||||
{ "team",
|
||||
s =>
|
||||
{
|
||||
int team;
|
||||
if (!int.TryParse(s, out team)) { Log.Write("server", "Invalid team: {0}", s ); return false; }
|
||||
|
||||
GetClient(conn).Team = team;
|
||||
SyncLobbyInfo();
|
||||
return true;
|
||||
}},
|
||||
{ "spawn",
|
||||
s =>
|
||||
{
|
||||
int spawnPoint;
|
||||
if (!int.TryParse(s, out spawnPoint) || spawnPoint < 0 || spawnPoint > 8) //TODO: SET properly!
|
||||
{
|
||||
Log.Write("server", "Invalid spawn point: {0}", s);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lobbyInfo.Clients.Where( c => c != GetClient(conn) ).Any( c => (c.SpawnPoint == spawnPoint) && (c.SpawnPoint != 0) ))
|
||||
{
|
||||
SendChatTo( conn, "You can't be at the same spawn point as another player" );
|
||||
return true;
|
||||
}
|
||||
|
||||
GetClient(conn).SpawnPoint = spawnPoint;
|
||||
SyncLobbyInfo();
|
||||
return true;
|
||||
}},
|
||||
{ "color",
|
||||
s =>
|
||||
{
|
||||
var c = s.Split(',').Select(cc => int.Parse(cc)).ToArray();
|
||||
GetClient(conn).Color1 = Color.FromArgb(c[0],c[1],c[2]);
|
||||
GetClient(conn).Color2 = Color.FromArgb(c[3],c[4],c[5]);
|
||||
SyncLobbyInfo();
|
||||
return true;
|
||||
}},
|
||||
{ "slot",
|
||||
s =>
|
||||
{
|
||||
int slot;
|
||||
if (!int.TryParse(s, out slot)) { Log.Write("server", "Invalid slot: {0}", s ); return false; }
|
||||
|
||||
var slotData = lobbyInfo.Slots.FirstOrDefault( x => x.Index == slot );
|
||||
if (slotData == null || slotData.Closed || slotData.Bot != null
|
||||
|| lobbyInfo.Clients.Any( c => c.Slot == slot ))
|
||||
return false;
|
||||
|
||||
GetClient(conn).Slot = slot;
|
||||
SyncLobbyInfo();
|
||||
return true;
|
||||
}},
|
||||
{ "slot_close",
|
||||
s =>
|
||||
{
|
||||
int slot;
|
||||
if (!int.TryParse(s, out slot)) { Log.Write("server", "Invalid slot: {0}", s ); return false; }
|
||||
|
||||
var slotData = lobbyInfo.Slots.FirstOrDefault( x => x.Index == slot );
|
||||
if (slotData == null)
|
||||
return false;
|
||||
|
||||
if (conn.PlayerIndex != 0)
|
||||
{
|
||||
SendChatTo( conn, "Only the host can alter slots" );
|
||||
return true;
|
||||
}
|
||||
|
||||
slotData.Closed = true;
|
||||
slotData.Bot = null;
|
||||
|
||||
/* kick any player that's in the slot */
|
||||
var occupant = lobbyInfo.Clients.FirstOrDefault( c => c.Slot == slotData.Index );
|
||||
if (occupant != null)
|
||||
{
|
||||
var occupantConn = conns.FirstOrDefault( c => c.PlayerIndex == occupant.Index );
|
||||
if (occupantConn != null)
|
||||
DropClient( occupantConn, new Exception() );
|
||||
}
|
||||
|
||||
SyncLobbyInfo();
|
||||
return true;
|
||||
}},
|
||||
{ "slot_open",
|
||||
s =>
|
||||
{
|
||||
int slot;
|
||||
if (!int.TryParse(s, out slot)) { Log.Write("server", "Invalid slot: {0}", s ); return false; }
|
||||
|
||||
var slotData = lobbyInfo.Slots.FirstOrDefault( x => x.Index == slot );
|
||||
if (slotData == null)
|
||||
return false;
|
||||
|
||||
if (conn.PlayerIndex != 0)
|
||||
{
|
||||
SendChatTo( conn, "Only the host can alter slots" );
|
||||
return true;
|
||||
}
|
||||
|
||||
slotData.Closed = false;
|
||||
slotData.Bot = null;
|
||||
|
||||
SyncLobbyInfo();
|
||||
return true;
|
||||
}},
|
||||
{ "slot_bot",
|
||||
s =>
|
||||
{
|
||||
var parts = s.Split(' ');
|
||||
|
||||
if (parts.Length != 2)
|
||||
{
|
||||
SendChatTo( conn, "Malformed slot_bot command" );
|
||||
return true;
|
||||
}
|
||||
|
||||
int slot;
|
||||
if (!int.TryParse(parts[0], out slot)) { Log.Write("server", "Invalid slot: {0}", s ); return false; }
|
||||
|
||||
var slotData = lobbyInfo.Slots.FirstOrDefault( x => x.Index == slot );
|
||||
if (slotData == null)
|
||||
return false;
|
||||
|
||||
if (conn.PlayerIndex != 0)
|
||||
{
|
||||
SendChatTo( conn, "Only the host can alter slots" );
|
||||
return true;
|
||||
}
|
||||
|
||||
slotData.Bot = parts[1];
|
||||
|
||||
SyncLobbyInfo();
|
||||
return true;
|
||||
}},
|
||||
{ "map",
|
||||
s =>
|
||||
{
|
||||
if (conn.PlayerIndex != 0)
|
||||
{
|
||||
SendChatTo( conn, "Only the host can change the map" );
|
||||
return true;
|
||||
}
|
||||
lobbyInfo.GlobalSettings.Map = s;
|
||||
LoadMap();
|
||||
|
||||
foreach(var client in lobbyInfo.Clients)
|
||||
{
|
||||
client.SpawnPoint = 0;
|
||||
client.State = Session.ClientState.NotReady;
|
||||
}
|
||||
|
||||
SyncLobbyInfo();
|
||||
return true;
|
||||
}},
|
||||
{ "mods",
|
||||
s =>
|
||||
{
|
||||
var args = s.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToList();
|
||||
lobbyInfo.GlobalSettings.Mods = args.GetRange(0,args.Count - 1).ToArray();
|
||||
lobbyInfo.GlobalSettings.Map = args.Last();
|
||||
SyncLobbyInfo();
|
||||
return true;
|
||||
}},
|
||||
{ "lockteams",
|
||||
s =>
|
||||
{
|
||||
if (conn.PlayerIndex != 0)
|
||||
{
|
||||
SendChatTo( conn, "Only the host can set that option" );
|
||||
return true;
|
||||
}
|
||||
|
||||
bool.TryParse(s, out lobbyInfo.GlobalSettings.LockTeams);
|
||||
SyncLobbyInfo();
|
||||
return true;
|
||||
}},
|
||||
};
|
||||
|
||||
var cmdName = cmd.Split(' ').First();
|
||||
var cmdValue = string.Join(" ", cmd.Split(' ').Skip(1).ToArray());
|
||||
|
||||
Func<string,bool> a;
|
||||
if (!dict.TryGetValue(cmdName, out a))
|
||||
return false;
|
||||
|
||||
Log.Write("server", "Client {0} sent server command: {1}", conn.PlayerIndex, cmd );
|
||||
return a(cmdValue);
|
||||
}
|
||||
|
||||
static void SendChatTo(Connection conn, string text)
|
||||
|
||||
public void SendChatTo(Connection conn, string text)
|
||||
{
|
||||
DispatchOrdersToClient(conn, 0, 0,
|
||||
new ServerOrder("Chat", text).Serialize());
|
||||
}
|
||||
|
||||
static void SendChat(Connection asConn, string text)
|
||||
{
|
||||
DispatchOrders(asConn, 0, new ServerOrder("Chat", text).Serialize());
|
||||
}
|
||||
public void SendChat(Connection asConn, string text)
|
||||
{
|
||||
DispatchOrders(asConn, 0, new ServerOrder("Chat", text).Serialize());
|
||||
}
|
||||
|
||||
static void InterpretServerOrder(Connection conn, ServerOrder so)
|
||||
public void SendDisconnected(Connection asConn)
|
||||
{
|
||||
DispatchOrders(asConn, 0, new ServerOrder("Disconnected", "").Serialize());
|
||||
}
|
||||
|
||||
void InterpretServerOrder(Connection conn, ServerOrder so)
|
||||
{
|
||||
switch (so.Name)
|
||||
{
|
||||
case "Command":
|
||||
{
|
||||
if(GameStarted)
|
||||
SendChatTo(conn, "Cannot change state when game started.");
|
||||
else if (GetClient(conn).State == Session.ClientState.Ready && !(so.Data == "ready" || so.Data == "startgame") )
|
||||
SendChatTo(conn, "Cannot change state when marked as ready.");
|
||||
else if (!InterpretCommand(conn, so.Data))
|
||||
{
|
||||
Log.Write("server", "Bad server command: {0}", so.Data);
|
||||
SendChatTo(conn, "Bad server command.");
|
||||
};
|
||||
}
|
||||
break;
|
||||
bool handled = false;
|
||||
foreach (var t in ServerTraits.WithInterface<IInterpretCommand>())
|
||||
if ((handled = t.InterpretCommand(this, conn, GetClient(conn), so.Data)))
|
||||
break;
|
||||
|
||||
if (!handled)
|
||||
{
|
||||
Log.Write("server", "Unknown server command: {0}", so.Data);
|
||||
SendChatTo(conn, "Unknown server command: {0}".F(so.Data));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case "Chat":
|
||||
case "Chat":
|
||||
case "TeamChat":
|
||||
foreach (var c in conns.Except(conn).ToArray())
|
||||
DispatchOrdersToClient(c, GetClient(conn).Index, 0, so.Serialize());
|
||||
@@ -569,16 +272,19 @@ namespace OpenRA.Server
|
||||
}
|
||||
}
|
||||
|
||||
static Session.Client GetClient(Connection conn)
|
||||
public Session.Client GetClient(Connection conn)
|
||||
{
|
||||
return lobbyInfo.Clients.First(c => c.Index == conn.PlayerIndex);
|
||||
}
|
||||
|
||||
public static void DropClient(Connection toDrop, Exception e)
|
||||
public void DropClient(Connection toDrop, Exception e)
|
||||
{
|
||||
conns.Remove(toDrop);
|
||||
SendChat(toDrop, "Connection Dropped");
|
||||
|
||||
if (GameStarted)
|
||||
SendDisconnected(toDrop); /* Report disconnection */
|
||||
|
||||
lobbyInfo.Clients.RemoveAll(c => c.Index == toDrop.PlayerIndex);
|
||||
|
||||
DispatchOrders( toDrop, toDrop.MostRecentFrame, new byte[] { 0xbf } );
|
||||
@@ -587,60 +293,28 @@ namespace OpenRA.Server
|
||||
SyncLobbyInfo();
|
||||
}
|
||||
|
||||
static void SyncLobbyInfo()
|
||||
public void SyncLobbyInfo()
|
||||
{
|
||||
if (!GameStarted) /* don't do this while the game is running, it breaks things. */
|
||||
DispatchOrders(null, 0,
|
||||
new ServerOrder("SyncInfo", lobbyInfo.Serialize()).Serialize());
|
||||
|
||||
PingMasterServer();
|
||||
foreach (var t in ServerTraits.WithInterface<INotifySyncLobbyInfo>())
|
||||
t.LobbyInfoSynced(this);
|
||||
}
|
||||
|
||||
static volatile bool isBusy;
|
||||
static Queue<string> masterServerMessages = new Queue<string>();
|
||||
static void PingMasterServer()
|
||||
|
||||
public void StartGame()
|
||||
{
|
||||
if (isBusy || !isInternetServer) return;
|
||||
GameStarted = true;
|
||||
foreach( var c in conns )
|
||||
foreach( var d in conns )
|
||||
DispatchOrdersToClient( c, d.PlayerIndex, 0x7FFFFFFF, new byte[] { 0xBF } );
|
||||
|
||||
lastPing = Environment.TickCount;
|
||||
isBusy = true;
|
||||
DispatchOrders(null, 0,
|
||||
new ServerOrder("StartGame", "").Serialize());
|
||||
|
||||
Action a = () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var url = "ping.php?port={0}&name={1}&state={2}&players={3}&mods={4}&map={5}";
|
||||
if (isInitialPing) url += "&new=1";
|
||||
|
||||
using (var wc = new WebClient())
|
||||
{
|
||||
wc.DownloadData(
|
||||
masterServerUrl + url.F(
|
||||
ExternalPort, Uri.EscapeUriString(Name),
|
||||
GameStarted ? 2 : 1, // todo: post-game states, etc.
|
||||
lobbyInfo.Clients.Count,
|
||||
string.Join(",", lobbyInfo.GlobalSettings.Mods),
|
||||
lobbyInfo.GlobalSettings.Map));
|
||||
|
||||
if (isInitialPing)
|
||||
{
|
||||
isInitialPing = false;
|
||||
lock (masterServerMessages)
|
||||
masterServerMessages.Enqueue("Master server communication established.");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Log.Write("server", ex.ToString());
|
||||
lock( masterServerMessages )
|
||||
masterServerMessages.Enqueue( "Master server communication failed." );
|
||||
}
|
||||
|
||||
isBusy = false;
|
||||
};
|
||||
|
||||
a.BeginInvoke(null, null);
|
||||
foreach (var t in ServerTraits.WithInterface<IStartGame>())
|
||||
t.GameStarted(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
58
OpenRA.Game/Server/TraitInterfaces.cs
Normal file
58
OpenRA.Game/Server/TraitInterfaces.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
#endregion
|
||||
using System;
|
||||
using OpenRA.Network;
|
||||
|
||||
namespace OpenRA.Server
|
||||
{
|
||||
// Returns true if order is handled
|
||||
public interface IInterpretCommand { bool InterpretCommand(Server server, Connection conn, Session.Client client, string cmd); }
|
||||
public interface INotifySyncLobbyInfo { void LobbyInfoSynced(Server server); }
|
||||
public interface INotifyServerStart { void ServerStarted(Server server); }
|
||||
public interface INotifyServerShutdown { void ServerShutdown(Server server); }
|
||||
public interface IStartGame { void GameStarted(Server server); }
|
||||
public interface IClientJoined { void ClientJoined(Server server, Connection conn); }
|
||||
public interface ITick
|
||||
{
|
||||
void Tick(Server server);
|
||||
int TickTimeout { get; }
|
||||
}
|
||||
|
||||
public abstract class ServerTrait {}
|
||||
|
||||
public class DebugServerTrait : ServerTrait, IInterpretCommand, IStartGame, INotifySyncLobbyInfo, INotifyServerStart, INotifyServerShutdown
|
||||
{
|
||||
public bool InterpretCommand(Server server, Connection conn, Session.Client client, string cmd)
|
||||
{
|
||||
Console.WriteLine("Server received command from player {1}: {0}",cmd, conn.PlayerIndex);
|
||||
return false;
|
||||
}
|
||||
|
||||
public void GameStarted(Server server)
|
||||
{
|
||||
Console.WriteLine("GameStarted()");
|
||||
}
|
||||
|
||||
public void LobbyInfoSynced(Server server)
|
||||
{
|
||||
Console.WriteLine("LobbyInfoSynced()");
|
||||
}
|
||||
|
||||
public void ServerStarted(Server server)
|
||||
{
|
||||
Console.WriteLine("ServerStarted()");
|
||||
}
|
||||
|
||||
public void ServerShutdown(Server server)
|
||||
{
|
||||
Console.WriteLine("ServerShutdown()");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,60 +48,49 @@ namespace OpenRA
|
||||
|
||||
public static void SetListenerPosition(float2 position) { soundEngine.SetListenerPosition(position); }
|
||||
|
||||
public static void Play(string name)
|
||||
static ISound Play(Player player, string name, bool headRelative, float2 pos, float volumeModifier)
|
||||
{
|
||||
if (player != null && player != player.World.LocalPlayer)
|
||||
return null;
|
||||
if (name == "" || name == null)
|
||||
return;
|
||||
return null;
|
||||
|
||||
var sound = sounds[name];
|
||||
soundEngine.Play2D(sound, false, true, float2.Zero, SoundVolume);
|
||||
}
|
||||
|
||||
public static void Play(string name, float2 pos)
|
||||
{
|
||||
if (name == "" || name == null)
|
||||
return;
|
||||
|
||||
var sound = sounds[name];
|
||||
soundEngine.Play2D(sound, false, false, pos, SoundVolume);
|
||||
}
|
||||
|
||||
public static void PlayToPlayer(Player player, string name)
|
||||
{
|
||||
if( player == player.World.LocalPlayer )
|
||||
Play( name );
|
||||
}
|
||||
|
||||
public static void PlayToPlayer(Player player, string name, float2 pos)
|
||||
{
|
||||
if (player == player.World.LocalPlayer)
|
||||
Play(name, pos);
|
||||
return soundEngine.Play2D(sounds[name],
|
||||
false, headRelative, pos,
|
||||
InternalSoundVolume * volumeModifier);
|
||||
}
|
||||
|
||||
public static ISound Play(string name) { return Play(null, name, true, float2.Zero, 1); }
|
||||
public static ISound Play(string name, float2 pos) { return Play(null, name, false, pos, 1); }
|
||||
public static ISound Play(string name, float volumeModifier) { return Play(null, name, true, float2.Zero, volumeModifier); }
|
||||
public static ISound Play(string name, float2 pos, float volumeModifier) { return Play(null, name, false, pos, volumeModifier); }
|
||||
public static ISound PlayToPlayer(Player player, string name) { return Play( player, name, true, float2.Zero, 1); }
|
||||
public static ISound PlayToPlayer(Player player, string name, float2 pos) { return Play(player, name, false, pos, 1); }
|
||||
|
||||
public static void PlayVideo(byte[] raw)
|
||||
{
|
||||
rawSource = LoadSoundRaw(raw);
|
||||
video = soundEngine.Play2D(rawSource, false, true, float2.Zero, SoundVolume);
|
||||
video = soundEngine.Play2D(rawSource, false, true, float2.Zero, InternalSoundVolume);
|
||||
}
|
||||
|
||||
|
||||
public static void PlayVideo()
|
||||
{
|
||||
if (video != null)
|
||||
soundEngine.PauseSound(video, false);
|
||||
}
|
||||
|
||||
|
||||
public static void PauseVideo()
|
||||
{
|
||||
if (video != null)
|
||||
soundEngine.PauseSound(video, true);
|
||||
}
|
||||
|
||||
|
||||
public static void StopVideo()
|
||||
{
|
||||
if (video != null)
|
||||
soundEngine.StopSound(video);
|
||||
}
|
||||
|
||||
|
||||
public static void Tick()
|
||||
{
|
||||
// Song finished
|
||||
@@ -111,13 +100,13 @@ namespace OpenRA
|
||||
OnMusicComplete();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static Action OnMusicComplete;
|
||||
public static bool MusicPlaying { get; private set; }
|
||||
|
||||
|
||||
public static void PlayMusic(string name)
|
||||
{
|
||||
PlayMusicThen(name, () => {});
|
||||
PlayMusicThen(name, () => { });
|
||||
}
|
||||
public static void PlayMusicThen(string name, Action then)
|
||||
{
|
||||
@@ -132,13 +121,13 @@ namespace OpenRA
|
||||
return;
|
||||
}
|
||||
StopMusic();
|
||||
|
||||
|
||||
currentMusic = name;
|
||||
MusicPlaying = true;
|
||||
var sound = sounds[name];
|
||||
music = soundEngine.Play2D(sound, false, true, float2.Zero, MusicVolume);
|
||||
}
|
||||
|
||||
|
||||
public static void PlayMusic()
|
||||
{
|
||||
if (music == null)
|
||||
@@ -147,20 +136,26 @@ namespace OpenRA
|
||||
soundEngine.PauseSound(music, false);
|
||||
}
|
||||
|
||||
public static void StopSound(ISound sound)
|
||||
{
|
||||
if (sound != null)
|
||||
soundEngine.StopSound(sound);
|
||||
}
|
||||
|
||||
public static void StopMusic()
|
||||
{
|
||||
if (music != null)
|
||||
soundEngine.StopSound(music);
|
||||
|
||||
|
||||
MusicPlaying = false;
|
||||
currentMusic = null;
|
||||
}
|
||||
|
||||
|
||||
public static void PauseMusic()
|
||||
{
|
||||
if (music == null)
|
||||
return;
|
||||
|
||||
|
||||
MusicPlaying = false;
|
||||
soundEngine.PauseSound(music, true);
|
||||
}
|
||||
@@ -168,16 +163,28 @@ namespace OpenRA
|
||||
public static float GlobalVolume
|
||||
{
|
||||
get { return soundEngine.Volume; }
|
||||
set { soundEngine.Volume = value;}
|
||||
set { soundEngine.Volume = value; }
|
||||
}
|
||||
|
||||
|
||||
static float soundVolumeModifier = 1.0f;
|
||||
public static float SoundVolumeModifier
|
||||
{
|
||||
get { return soundVolumeModifier; }
|
||||
set
|
||||
{
|
||||
soundVolumeModifier = value;
|
||||
soundEngine.SetSoundVolume(InternalSoundVolume, music, video);
|
||||
}
|
||||
}
|
||||
|
||||
static float InternalSoundVolume { get { return SoundVolume * soundVolumeModifier; } }
|
||||
public static float SoundVolume
|
||||
{
|
||||
get { return Game.Settings.Sound.SoundVolume; }
|
||||
set
|
||||
{
|
||||
Game.Settings.Sound.SoundVolume = value;
|
||||
soundEngine.SetSoundVolume(value, music, video);
|
||||
soundEngine.SetSoundVolume(InternalSoundVolume, music, video);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,7 +198,7 @@ namespace OpenRA
|
||||
music.Volume = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static float VideoVolume
|
||||
{
|
||||
get { return Game.Settings.Sound.VideoVolume; }
|
||||
@@ -202,17 +209,17 @@ namespace OpenRA
|
||||
video.Volume = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static float MusicSeekPosition
|
||||
{
|
||||
get { return (music != null)? music.SeekPosition : 0; }
|
||||
get { return (music != null) ? music.SeekPosition : 0; }
|
||||
}
|
||||
|
||||
|
||||
public static float VideoSeekPosition
|
||||
{
|
||||
get { return (video != null)? video.SeekPosition : 0; }
|
||||
get { return (video != null) ? video.SeekPosition : 0; }
|
||||
}
|
||||
|
||||
|
||||
// Returns true if it played a phrase
|
||||
public static bool PlayVoice(string phrase, Actor voicedUnit, string variant)
|
||||
{
|
||||
@@ -228,9 +235,9 @@ namespace OpenRA
|
||||
var clip = vi.Pools.Value[phrase].GetNext();
|
||||
if (clip == null)
|
||||
return false;
|
||||
|
||||
var variantext = (vi.Variants.ContainsKey(variant) && !vi.DisableVariants.Contains(phrase))?
|
||||
vi.Variants[variant][voicedUnit.ActorID % vi.Variants.Count] : vi.DefaultVariant;
|
||||
|
||||
var variantext = (vi.Variants.ContainsKey(variant) && !vi.DisableVariants.Contains(phrase)) ?
|
||||
vi.Variants[variant][voicedUnit.ActorID % vi.Variants[variant].Length] : vi.DefaultVariant;
|
||||
Play(clip + variantext);
|
||||
return true;
|
||||
}
|
||||
@@ -249,8 +256,9 @@ namespace OpenRA
|
||||
void SetSoundVolume(float volume, ISound music, ISound video);
|
||||
}
|
||||
|
||||
interface ISoundSource {}
|
||||
interface ISound
|
||||
interface ISoundSource { }
|
||||
|
||||
public interface ISound
|
||||
{
|
||||
float Volume { get; set; }
|
||||
float SeekPosition { get; }
|
||||
@@ -283,7 +291,7 @@ namespace OpenRA
|
||||
Log.Write("debug", "Failed generating OpenAL source {0}", i);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
sourcePool.Add(source, false);
|
||||
}
|
||||
}
|
||||
@@ -335,10 +343,10 @@ namespace OpenRA
|
||||
get { return volume; }
|
||||
set { Al.alListenerf(Al.AL_GAIN, volume = value); }
|
||||
}
|
||||
|
||||
|
||||
public void PauseSound(ISound sound, bool paused)
|
||||
{
|
||||
int key = ((OpenAlSound) sound).source;
|
||||
int key = ((OpenAlSound)sound).source;
|
||||
int state;
|
||||
Al.alGetSourcei(key, Al.AL_SOURCE_STATE, out state);
|
||||
if (state == Al.AL_PLAYING && paused)
|
||||
@@ -346,9 +354,9 @@ namespace OpenRA
|
||||
else if (state == Al.AL_PAUSED && !paused)
|
||||
Al.alSourcePlay(key);
|
||||
}
|
||||
|
||||
|
||||
public void SetAllSoundsPaused(bool paused)
|
||||
{
|
||||
{
|
||||
foreach (int key in sourcePool.Keys)
|
||||
{
|
||||
int state;
|
||||
@@ -357,35 +365,35 @@ namespace OpenRA
|
||||
Al.alSourcePause(key);
|
||||
else if (state == Al.AL_PAUSED && !paused)
|
||||
Al.alSourcePlay(key);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void SetSoundVolume(float volume, ISound music, ISound video)
|
||||
{
|
||||
var sounds = sourcePool.Select(s => s.Key).Where( b =>
|
||||
{
|
||||
var sounds = sourcePool.Select(s => s.Key).Where(b =>
|
||||
{
|
||||
int state;
|
||||
Al.alGetSourcei(b, Al.AL_SOURCE_STATE, out state);
|
||||
return ((state == Al.AL_PLAYING || state == Al.AL_PAUSED) &&
|
||||
((music != null)? b != ((OpenAlSound) music).source : true) &&
|
||||
((video != null)? b != ((OpenAlSound) video).source : true));
|
||||
return ((state == Al.AL_PLAYING || state == Al.AL_PAUSED) &&
|
||||
((music != null) ? b != ((OpenAlSound)music).source : true) &&
|
||||
((video != null) ? b != ((OpenAlSound)video).source : true));
|
||||
}).ToList();
|
||||
foreach (var s in sounds)
|
||||
{
|
||||
Al.alSourcef(s, Al.AL_GAIN, volume);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void StopSound(ISound sound)
|
||||
{
|
||||
int key = ((OpenAlSound) sound).source;
|
||||
int key = ((OpenAlSound)sound).source;
|
||||
int state;
|
||||
Al.alGetSourcei(key, Al.AL_SOURCE_STATE, out state);
|
||||
if (state == Al.AL_PLAYING || state == Al.AL_PAUSED)
|
||||
Al.alSourceStop(key);
|
||||
}
|
||||
|
||||
|
||||
public void StopAllSounds()
|
||||
{
|
||||
foreach (int key in sourcePool.Keys)
|
||||
@@ -399,7 +407,7 @@ namespace OpenRA
|
||||
|
||||
public void SetListenerPosition(float2 position)
|
||||
{
|
||||
var orientation = new [] { 0f, 0f, 1f, 0f, -1f, 0f };
|
||||
var orientation = new[] { 0f, 0f, 1f, 0f, -1f, 0f };
|
||||
|
||||
Al.alListener3f(Al.AL_POSITION, position.X, position.Y, 50);
|
||||
Al.alListenerfv(Al.AL_ORIENTATION, ref orientation[0]);
|
||||
@@ -451,26 +459,26 @@ namespace OpenRA
|
||||
public float Volume
|
||||
{
|
||||
get { return volume; }
|
||||
set
|
||||
set
|
||||
{
|
||||
if (source != -1)
|
||||
Al.alSourcef(source, Al.AL_GAIN, volume = value);
|
||||
Al.alSourcef(source, Al.AL_GAIN, volume = value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public float SeekPosition
|
||||
{
|
||||
get
|
||||
{
|
||||
float pos;
|
||||
Al.alGetSourcef(source, Al.AL_SAMPLE_OFFSET, out pos);
|
||||
return pos/22050f;
|
||||
return pos / 22050f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public bool Playing
|
||||
{
|
||||
get
|
||||
get
|
||||
{
|
||||
int state;
|
||||
Al.alGetSourcei(source, Al.AL_SOURCE_STATE, out state);
|
||||
|
||||
@@ -90,7 +90,7 @@ namespace OpenRA.Support
|
||||
}
|
||||
}
|
||||
|
||||
class PerfSample : IDisposable
|
||||
public class PerfSample : IDisposable
|
||||
{
|
||||
readonly Stopwatch sw = new Stopwatch();
|
||||
readonly string Item;
|
||||
|
||||
38
OpenRA.Game/Traits/Activities/CancelableActivity.cs
Executable file
38
OpenRA.Game/Traits/Activities/CancelableActivity.cs
Executable file
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
public abstract class CancelableActivity : IActivity
|
||||
{
|
||||
protected IActivity NextActivity { get; private set; }
|
||||
protected bool IsCanceled { get; private set; }
|
||||
|
||||
public abstract IActivity Tick( Actor self );
|
||||
protected virtual bool OnCancel( Actor self ) { return true; }
|
||||
|
||||
public void Cancel( Actor self )
|
||||
{
|
||||
IsCanceled = OnCancel( self );
|
||||
if( IsCanceled )
|
||||
NextActivity = null;
|
||||
else if (NextActivity != null)
|
||||
NextActivity.Cancel( self );
|
||||
}
|
||||
|
||||
public void Queue( IActivity activity )
|
||||
{
|
||||
if( NextActivity != null )
|
||||
NextActivity.Queue( activity );
|
||||
else
|
||||
NextActivity = activity;
|
||||
}
|
||||
|
||||
public virtual IEnumerable<float2> GetCurrentPath()
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,6 @@ namespace OpenRA.Traits.Activities
|
||||
{
|
||||
public class Idle : CancelableActivity
|
||||
{
|
||||
public override IActivity Tick(Actor self) { return NextActivity; }
|
||||
public override IActivity Tick(Actor self) { return NextActivity ?? this; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.Effects;
|
||||
using OpenRA.GameRules;
|
||||
using OpenRA.Traits.Activities;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
public class BuildingInfo : ITraitInfo
|
||||
{
|
||||
public readonly int Power = 0;
|
||||
public readonly bool BaseNormal = true;
|
||||
public readonly bool WaterBound = false;
|
||||
public readonly int Adjacent = 2;
|
||||
public readonly bool Capturable = false;
|
||||
public readonly string Footprint = "x";
|
||||
public readonly int2 Dimensions = new int2(1, 1);
|
||||
public readonly bool Unsellable = false;
|
||||
public readonly float RefundPercent = 0.5f;
|
||||
|
||||
public readonly string[] BuildSounds = {"placbldg.aud", "build5.aud"};
|
||||
public readonly string[] SellSounds = {"cashturn.aud"};
|
||||
public readonly string DamagedSound = "kaboom1.aud";
|
||||
public readonly string DestroyedSound = "kaboom22.aud";
|
||||
|
||||
public object Create(ActorInitializer init) { return new Building(init); }
|
||||
}
|
||||
|
||||
public class Building : INotifyDamage, IResolveOrder, IOccupySpace
|
||||
{
|
||||
readonly Actor self;
|
||||
public readonly BuildingInfo Info;
|
||||
[Sync]
|
||||
readonly int2 topLeft;
|
||||
|
||||
readonly PowerManager PlayerPower;
|
||||
|
||||
public int2 PxPosition { get { return ( 2 * topLeft + Info.Dimensions ) * Game.CellSize / 2; } }
|
||||
|
||||
public Building(ActorInitializer init)
|
||||
{
|
||||
this.self = init.self;
|
||||
this.topLeft = init.Get<LocationInit,int2>();
|
||||
Info = self.Info.Traits.Get<BuildingInfo>();
|
||||
|
||||
PlayerPower = init.self.Owner.PlayerActor.Trait<PowerManager>();
|
||||
}
|
||||
|
||||
public int GetPowerUsage()
|
||||
{
|
||||
if (Info.Power <= 0)
|
||||
return Info.Power;
|
||||
|
||||
var health = self.TraitOrDefault<Health>();
|
||||
return health != null ? (Info.Power * health.HP / health.MaxHP) : Info.Power;
|
||||
}
|
||||
|
||||
public void Damaged(Actor self, AttackInfo e)
|
||||
{
|
||||
// Power plants lose power with damage
|
||||
if (Info.Power > 0)
|
||||
PlayerPower.UpdateActor(self, GetPowerUsage());
|
||||
|
||||
if (e.DamageState == DamageState.Dead)
|
||||
{
|
||||
self.World.WorldActor.Trait<ScreenShaker>().AddEffect(10, self.CenterLocation, 1);
|
||||
Sound.Play(Info.DestroyedSound, self.CenterLocation);
|
||||
}
|
||||
}
|
||||
|
||||
public void ResolveOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString == "Sell")
|
||||
{
|
||||
self.CancelActivity();
|
||||
self.QueueActivity(new Sell());
|
||||
}
|
||||
}
|
||||
|
||||
public int2 TopLeft
|
||||
{
|
||||
get { return topLeft; }
|
||||
}
|
||||
|
||||
public IEnumerable<int2> OccupiedCells()
|
||||
{
|
||||
return Footprint.UnpathableTiles( self.Info.Name, Info, TopLeft );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -57,9 +57,11 @@ namespace OpenRA.Traits
|
||||
return;
|
||||
|
||||
var p = target.CenterLocation;
|
||||
var move = self.TraitOrDefault<IMove>();
|
||||
var origin = move != null ? self.CenterLocation - new float2(0, move.Altitude) : self.CenterLocation;
|
||||
|
||||
Game.Renderer.LineRenderer.DrawLine(self.CenterLocation, p, c, c);
|
||||
for (bool b = false; !b; p = self.CenterLocation, b = true)
|
||||
Game.Renderer.LineRenderer.DrawLine(origin, p, c, c);
|
||||
for (bool b = false; !b; p = origin, b = true)
|
||||
{
|
||||
Game.Renderer.LineRenderer.DrawLine(p + new float2(-1, -1), p + new float2(-1, 1), c, c);
|
||||
Game.Renderer.LineRenderer.DrawLine(p + new float2(-1, 1), p + new float2(1, 1), c, c);
|
||||
|
||||
9
OpenRA.Game/Traits/BaseBuilding.cs → OpenRA.Game/Traits/EditorAppearance.cs
Executable file → Normal file
9
OpenRA.Game/Traits/BaseBuilding.cs → OpenRA.Game/Traits/EditorAppearance.cs
Executable file → Normal file
@@ -10,7 +10,10 @@
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
/* tag trait for "bases": mcv/fact */
|
||||
public class BaseBuildingInfo : TraitInfo<BaseBuilding> { }
|
||||
public class BaseBuilding { }
|
||||
public class EditorAppearanceInfo : TraitInfo<EditorAppearance>
|
||||
{
|
||||
public readonly bool RelativeToTopLeft = false;
|
||||
}
|
||||
|
||||
public class EditorAppearance { }
|
||||
}
|
||||
@@ -22,6 +22,7 @@ namespace OpenRA.Traits
|
||||
public class HealthInfo : ITraitInfo
|
||||
{
|
||||
public readonly int HP = 0;
|
||||
public readonly float Radius = 10;
|
||||
public virtual object Create(ActorInitializer init) { return new Health(init, this); }
|
||||
}
|
||||
|
||||
@@ -80,15 +81,15 @@ namespace OpenRA.Traits
|
||||
|
||||
var oldState = this.DamageState;
|
||||
|
||||
/* apply the damage modifiers, if we have any. */
|
||||
var modifier = (float)self.TraitsImplementing<IDamageModifier>()
|
||||
.Select(t => t.GetDamageModifier(warhead)).Product();
|
||||
/* apply the damage modifiers, if we have any. */
|
||||
var modifier = (float)self.TraitsImplementing<IDamageModifier>().Concat(self.Owner.PlayerActor.TraitsImplementing<IDamageModifier>())
|
||||
.Select(t => t.GetDamageModifier(attacker, warhead)).Product();
|
||||
|
||||
damage = (int)(damage * modifier);
|
||||
|
||||
hp -= damage;
|
||||
|
||||
foreach (var nd in self.TraitsImplementing<INotifyDamage>())
|
||||
hp -= damage;
|
||||
|
||||
foreach (var nd in self.TraitsImplementing<INotifyDamage>().Concat(self.Owner.PlayerActor.TraitsImplementing<INotifyDamage>()))
|
||||
nd.Damaged(self, new AttackInfo
|
||||
{
|
||||
Attacker = attacker,
|
||||
@@ -96,7 +97,9 @@ namespace OpenRA.Traits
|
||||
DamageState = this.DamageState,
|
||||
PreviousDamageState = oldState,
|
||||
DamageStateChanged = this.DamageState != oldState,
|
||||
Warhead = warhead
|
||||
Warhead = warhead,
|
||||
PreviousHealth = hp + damage < 0 ? 0 : hp + damage,
|
||||
Health = hp
|
||||
});
|
||||
|
||||
if (hp <= 0)
|
||||
|
||||
@@ -17,7 +17,8 @@ namespace OpenRA.Traits
|
||||
public bool FastBuild = false;
|
||||
public bool FastCharge = false;
|
||||
public bool DisableShroud = false;
|
||||
public bool PathDebug = false;
|
||||
public bool PathDebug = false;
|
||||
public bool UnitInfluenceDebug = false;
|
||||
|
||||
public object Create (ActorInitializer init) { return new DeveloperMode(this); }
|
||||
}
|
||||
@@ -30,14 +31,16 @@ namespace OpenRA.Traits
|
||||
[Sync] public bool FastBuild;
|
||||
[Sync] public bool DisableShroud;
|
||||
[Sync] public bool PathDebug;
|
||||
|
||||
[Sync] public bool UnitInfluenceDebug;
|
||||
|
||||
public DeveloperMode(DeveloperModeInfo info)
|
||||
{
|
||||
Info = info;
|
||||
FastBuild = Info.FastBuild;
|
||||
FastCharge = Info.FastCharge;
|
||||
DisableShroud = Info.DisableShroud;
|
||||
PathDebug = Info.PathDebug;
|
||||
PathDebug = Info.PathDebug;
|
||||
UnitInfluenceDebug = info.UnitInfluenceDebug;
|
||||
}
|
||||
|
||||
public void ResolveOrder (Actor self, Order order)
|
||||
@@ -79,9 +82,8 @@ namespace OpenRA.Traits
|
||||
break;
|
||||
}
|
||||
case "DevUnitDebug":
|
||||
{
|
||||
if (self.World.LocalPlayer == self.Owner)
|
||||
Game.Settings.Debug.ShowCollisions ^= true;
|
||||
{
|
||||
UnitInfluenceDebug ^= true;
|
||||
break;
|
||||
}
|
||||
case "DevGiveExploration":
|
||||
|
||||
42
OpenRA.Game/Traits/Scale.cs
Normal file
42
OpenRA.Game/Traits/Scale.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
public class ScaleInfo : ITraitInfo
|
||||
{
|
||||
public readonly float Value = 1f; /* default */
|
||||
|
||||
public ScaleInfo() { } /* only because we have other ctors */
|
||||
|
||||
public object Create(ActorInitializer init) { return new Scale(init.self, this); }
|
||||
}
|
||||
|
||||
public class Scale : IRenderModifier
|
||||
{
|
||||
Actor self;
|
||||
public ScaleInfo Info { get; protected set; }
|
||||
|
||||
public Scale(Actor self, ScaleInfo info)
|
||||
{
|
||||
this.Info = info;
|
||||
this.self = self;
|
||||
}
|
||||
|
||||
public IEnumerable<Renderable> ModifyRender(Actor self, IEnumerable<Renderable> r)
|
||||
{
|
||||
var r2 = new List<Renderable>(r);
|
||||
var r3 = new List<Renderable>();
|
||||
|
||||
for (int i = 0; i < r2.Count;i++)
|
||||
{
|
||||
var renderable = r2[i];
|
||||
|
||||
renderable.Scale = Info.Value;
|
||||
r3.Add(renderable);
|
||||
// yield return renderable;
|
||||
}
|
||||
|
||||
return r3;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
#endregion
|
||||
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.Graphics;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
@@ -19,7 +20,6 @@ namespace OpenRA.Traits
|
||||
public readonly int[] Bounds = null;
|
||||
[VoiceReference]
|
||||
public readonly string Voice = null;
|
||||
public readonly float Radius = 10;
|
||||
}
|
||||
|
||||
public class Selectable : IPostRenderSelection
|
||||
@@ -31,13 +31,20 @@ namespace OpenRA.Traits
|
||||
public void RenderAfterWorld (WorldRenderer wr, Actor self)
|
||||
{
|
||||
var bounds = self.GetBounds(true);
|
||||
Color selectionColor = Color.White;
|
||||
|
||||
var xy = new float2(bounds.Left, bounds.Top);
|
||||
var Xy = new float2(bounds.Right, bounds.Top);
|
||||
var xY = new float2(bounds.Left, bounds.Bottom);
|
||||
var XY = new float2(bounds.Right, bounds.Bottom);
|
||||
|
||||
DrawSelectionBox(self, xy, Xy, xY, XY, Color.White);
|
||||
var colorResults = self.TraitsImplementing<ISelectionColorModifier>().Select(t => t.GetSelectionColorModifier(self, selectionColor)).Where(
|
||||
c => c.ToArgb() != selectionColor.ToArgb());
|
||||
|
||||
if (colorResults.Any())
|
||||
selectionColor = colorResults.First();
|
||||
|
||||
DrawSelectionBox(self, xy, Xy, xY, XY, selectionColor);
|
||||
DrawHealthBar(self, xy, Xy);
|
||||
DrawControlGroup(wr, self, xy);
|
||||
DrawPips(wr, self, xY);
|
||||
@@ -158,7 +165,7 @@ namespace OpenRA.Traits
|
||||
|
||||
void DrawUnitPath(Actor self)
|
||||
{
|
||||
if (!self.World.LocalPlayer.PlayerActor.Trait<DeveloperMode>().PathDebug) return;
|
||||
if (self.World.LocalPlayer == null ||!self.World.LocalPlayer.PlayerActor.Trait<DeveloperMode>().PathDebug) return;
|
||||
|
||||
var activity = self.GetCurrentActivity();
|
||||
var mobile = self.TraitOrDefault<IMove>();
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Drawing;
|
||||
using OpenRA.Graphics;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
public class TargetableInfo : ITraitInfo
|
||||
{
|
||||
public readonly string[] TargetTypes = {};
|
||||
public virtual object Create( ActorInitializer init ) { return new Targetable(this); }
|
||||
}
|
||||
|
||||
public class Targetable : ITargetable
|
||||
{
|
||||
TargetableInfo Info;
|
||||
public Targetable(TargetableInfo info)
|
||||
{
|
||||
Info = info;
|
||||
}
|
||||
|
||||
public string[] TargetTypes
|
||||
{
|
||||
get { return Info.TargetTypes;}
|
||||
}
|
||||
}
|
||||
}
|
||||
110
OpenRA.Game/Traits/TraitsInterfaces.cs
Normal file → Executable file
110
OpenRA.Game/Traits/TraitsInterfaces.cs
Normal file → Executable file
@@ -13,6 +13,7 @@ using System.Drawing;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.GameRules;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Network;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
@@ -28,7 +29,9 @@ namespace OpenRA.Traits
|
||||
public int Damage;
|
||||
public DamageState DamageState;
|
||||
public DamageState PreviousDamageState;
|
||||
public bool DamageStateChanged;
|
||||
public bool DamageStateChanged;
|
||||
public int PreviousHealth;
|
||||
public int Health;
|
||||
}
|
||||
|
||||
public interface ITick { void Tick(Actor self); }
|
||||
@@ -36,20 +39,22 @@ namespace OpenRA.Traits
|
||||
public interface IIssueOrder
|
||||
{
|
||||
IEnumerable<IOrderTargeter> Orders { get; }
|
||||
Order IssueOrder( Actor self, IOrderTargeter order, Target target );
|
||||
Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued );
|
||||
}
|
||||
public interface IOrderTargeter
|
||||
{
|
||||
string OrderID { get; }
|
||||
int OrderPriority { get; }
|
||||
bool CanTargetUnit( Actor self, Actor target, bool forceAttack, bool forceMove, ref string cursor );
|
||||
bool CanTargetLocation( Actor self, int2 location, List<Actor> actorsAtLocation, bool forceAttack, bool forceMove, ref string cursor );
|
||||
bool CanTargetUnit( Actor self, Actor target, bool forceAttack, bool forceMove, bool forceQueue, ref string cursor );
|
||||
bool CanTargetLocation(Actor self, int2 location, List<Actor> actorsAtLocation, bool forceAttack, bool forceQueue, bool forceMove, ref string cursor);
|
||||
bool IsQueued { get; }
|
||||
}
|
||||
public interface IResolveOrder { void ResolveOrder(Actor self, Order order); }
|
||||
public interface IResolveOrder { void ResolveOrder(Actor self, Order order); }
|
||||
public interface IValidateOrder { bool OrderValidation(OrderManager orderManager, World world, int clientId, Order order);
|
||||
}
|
||||
public interface IOrderCursor { string CursorForOrder(Actor self, Order order); }
|
||||
public interface IOrderVoice { string VoicePhraseForOrder(Actor self, Order order); }
|
||||
public interface ITargetable { string[] TargetTypes { get; } }
|
||||
|
||||
public interface ICustomUnitOrderGenerator : IOrderGenerator {};
|
||||
public interface INotifySold { void Selling( Actor self ); void Sold( Actor self ); }
|
||||
public interface INotifyDamage { void Damaged(Actor self, AttackInfo e); }
|
||||
public interface INotifyBuildComplete { void BuildingComplete(Actor self); }
|
||||
@@ -100,11 +105,12 @@ namespace OpenRA.Traits
|
||||
}
|
||||
}
|
||||
|
||||
public interface INotifyAttack { void Attacking(Actor self); }
|
||||
public interface INotifyAttack { void Attacking(Actor self, Target target); }
|
||||
public interface IRenderModifier { IEnumerable<Renderable> ModifyRender(Actor self, IEnumerable<Renderable> r); }
|
||||
public interface IDamageModifier { float GetDamageModifier( WarheadInfo warhead ); }
|
||||
public interface ISpeedModifier { float GetSpeedModifier(); }
|
||||
public interface IDamageModifier { float GetDamageModifier(Actor attacker, WarheadInfo warhead); }
|
||||
public interface ISpeedModifier { decimal GetSpeedModifier(); }
|
||||
public interface IFirepowerModifier { float GetFirepowerModifier(); }
|
||||
public interface ISelectionColorModifier { Color GetSelectionColorModifier(Actor self, Color defaultColor); }
|
||||
public interface IPalette { void InitPalette( WorldRenderer wr ); }
|
||||
public interface IPaletteModifier { void AdjustPalette(Dictionary<string,Palette> b); }
|
||||
public interface IPips { IEnumerable<PipType> GetPips(Actor self); }
|
||||
@@ -143,22 +149,37 @@ namespace OpenRA.Traits
|
||||
public readonly string Palette;
|
||||
public readonly int Z;
|
||||
public readonly int ZOffset;
|
||||
public float Scale;
|
||||
|
||||
public Renderable(Sprite sprite, float2 pos, string palette, int z, int zOffset)
|
||||
{
|
||||
Sprite = sprite;
|
||||
Pos = pos;
|
||||
Palette = palette;
|
||||
Z = z;
|
||||
ZOffset = zOffset;
|
||||
}
|
||||
public Renderable(Sprite sprite, float2 pos, string palette, int z, int zOffset)
|
||||
{
|
||||
Sprite = sprite;
|
||||
Pos = pos;
|
||||
Palette = palette;
|
||||
Z = z;
|
||||
ZOffset = zOffset;
|
||||
Scale = 1f; /* default */
|
||||
}
|
||||
public Renderable(Sprite sprite, float2 pos, string palette, int z, int zOffset, float scale)
|
||||
{
|
||||
Sprite = sprite;
|
||||
Pos = pos;
|
||||
Palette = palette;
|
||||
Z = z;
|
||||
ZOffset = zOffset;
|
||||
Scale = scale; /* default */
|
||||
}
|
||||
|
||||
public Renderable(Sprite sprite, float2 pos, string palette, int z)
|
||||
: this(sprite, pos, palette, z, 0) { }
|
||||
public Renderable(Sprite sprite, float2 pos, string palette, int z)
|
||||
: this(sprite, pos, palette, z, 0) { }
|
||||
|
||||
public Renderable WithPalette(string newPalette) { return new Renderable(Sprite, Pos, newPalette, Z, ZOffset); }
|
||||
public Renderable WithZOffset(int newOffset) { return new Renderable(Sprite, Pos, Palette, Z, newOffset); }
|
||||
public Renderable WithPos(float2 newPos) { return new Renderable(Sprite, newPos, Palette, Z, ZOffset); }
|
||||
|
||||
public Renderable(Sprite sprite, float2 pos, string palette, int z, float scale)
|
||||
: this(sprite, pos, palette, z, 0, scale) { }
|
||||
|
||||
public Renderable WithPalette(string newPalette) { return new Renderable(Sprite, Pos, newPalette, Z, ZOffset, Scale); }
|
||||
public Renderable WithZOffset(int newOffset) { return new Renderable(Sprite, Pos, Palette, Z, newOffset, Scale); }
|
||||
public Renderable WithPos(float2 newPos) { return new Renderable(Sprite, newPos, Palette, Z, ZOffset, Scale); }
|
||||
}
|
||||
|
||||
public interface ITraitInfo { object Create(ActorInitializer init); }
|
||||
@@ -181,42 +202,13 @@ namespace OpenRA.Traits
|
||||
IEnumerable<float2> GetCurrentPath();
|
||||
}
|
||||
|
||||
public abstract class CancelableActivity : IActivity
|
||||
{
|
||||
protected IActivity NextActivity { get; private set; }
|
||||
protected bool IsCanceled { get; private set; }
|
||||
|
||||
public abstract IActivity Tick( Actor self );
|
||||
protected virtual bool OnCancel() { return true; }
|
||||
|
||||
public void Cancel( Actor self )
|
||||
{
|
||||
IsCanceled = OnCancel();
|
||||
if( IsCanceled )
|
||||
NextActivity = null;
|
||||
else if (NextActivity != null)
|
||||
NextActivity.Cancel( self );
|
||||
}
|
||||
|
||||
public void Queue( IActivity activity )
|
||||
{
|
||||
if( NextActivity != null )
|
||||
NextActivity.Queue( activity );
|
||||
else
|
||||
NextActivity = activity;
|
||||
}
|
||||
|
||||
public virtual IEnumerable<float2> GetCurrentPath()
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
|
||||
public interface IRenderOverlay { void Render( WorldRenderer wr ); }
|
||||
public interface INotifyIdle { void Idle(Actor self); }
|
||||
|
||||
public interface IBlocksBullets { }
|
||||
|
||||
public interface IPostRender { void RenderAfterWorld(WorldRenderer wr, Actor self); }
|
||||
|
||||
public interface IPostRenderSelection { void RenderAfterWorld(WorldRenderer wr, Actor self); }
|
||||
public interface IPreRenderSelection { void RenderBeforeWorld(WorldRenderer wr, Actor self); }
|
||||
|
||||
@@ -226,7 +218,7 @@ namespace OpenRA.Traits
|
||||
float2 pos;
|
||||
bool valid;
|
||||
|
||||
public static Target FromActor(Actor a) { return new Target { actor = a, valid = true }; }
|
||||
public static Target FromActor(Actor a) { return new Target { actor = a, valid = (a != null) }; }
|
||||
public static Target FromPos(float2 p) { return new Target { pos = p, valid = true }; }
|
||||
public static Target FromCell(int2 c) { return new Target { pos = Util.CenterOfCell(c), valid = true }; }
|
||||
public static Target FromOrder(Order o)
|
||||
@@ -245,4 +237,12 @@ namespace OpenRA.Traits
|
||||
public Actor Actor { get { return IsActor ? actor : null; } }
|
||||
public bool IsActor { get { return actor != null && !actor.Destroyed; } }
|
||||
}
|
||||
|
||||
public interface ITargetable
|
||||
{
|
||||
string[] TargetTypes { get; }
|
||||
IEnumerable<int2> TargetableCells( Actor self );
|
||||
}
|
||||
|
||||
public interface INotifyKeyPress { bool KeyPressed(Actor self, KeyInput e); }
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ using System;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Support;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
@@ -99,7 +100,13 @@ namespace OpenRA.Traits
|
||||
public static Renderable Centered(Actor self, Sprite s, float2 location)
|
||||
{
|
||||
var pal = self.Owner == null ? "player0" : self.Owner.Palette;
|
||||
var loc = location - 0.5f * s.size;
|
||||
var scale = self.TraitOrDefault<Scale>();
|
||||
var scaleModifier = 1f;
|
||||
if (scale != null)
|
||||
scaleModifier = scale.Info.Value;
|
||||
|
||||
var loc = location - 0.5f * s.size * scaleModifier;
|
||||
|
||||
return new Renderable(s, loc.Round(), pal, (int)self.CenterLocation.Y);
|
||||
}
|
||||
|
||||
@@ -109,6 +116,24 @@ namespace OpenRA.Traits
|
||||
(next, a) => { a.Queue( next ); return a; });
|
||||
}
|
||||
|
||||
public static IActivity RunActivity( Actor self, IActivity act )
|
||||
{
|
||||
while( act != null )
|
||||
{
|
||||
var prev = act;
|
||||
|
||||
var sw = new Stopwatch();
|
||||
act = act.Tick( self );
|
||||
var dt = sw.ElapsedTime();
|
||||
if(dt > Game.Settings.Debug.LongTickThreshold)
|
||||
Log.Write("perf", "[{2}] Activity: {0} ({1:0.000} ms)", prev, dt * 1000, Game.LocalTick);
|
||||
|
||||
if( prev == act )
|
||||
break;
|
||||
}
|
||||
return act;
|
||||
}
|
||||
|
||||
public static Color ArrayToColor(int[] x) { return Color.FromArgb(x[0], x[1], x[2]); }
|
||||
|
||||
public static int2 CellContaining(float2 pos) { return (1f / Game.CellSize * pos).ToInt2(); }
|
||||
|
||||
31
OpenRA.Game/Traits/ValidateOrder.cs
Normal file
31
OpenRA.Game/Traits/ValidateOrder.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using OpenRA.Network;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
public class ValidateOrderInfo : TraitInfo<ValidateOrder> { }
|
||||
|
||||
public class ValidateOrder : IValidateOrder
|
||||
{
|
||||
public bool OrderValidation(OrderManager orderManager, World world, int clientId, Order order)
|
||||
{
|
||||
// Drop exploiting orders
|
||||
if (order.Subject != null && order.Subject.Owner.ClientIndex != clientId)
|
||||
{
|
||||
Game.Debug("Detected exploit order from {0}: {1}".F(clientId, order.OrderString));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
public class ValuedInfo : TraitInfo<Valued>
|
||||
{
|
||||
public readonly int Cost = 0;
|
||||
}
|
||||
|
||||
public class TooltipInfo : TraitInfo<Tooltip>
|
||||
{
|
||||
public readonly string Description = "";
|
||||
public readonly string Name = "";
|
||||
public readonly string Icon = null;
|
||||
public readonly string[] AlternateName = { };
|
||||
}
|
||||
|
||||
public class Valued { }
|
||||
public class Tooltip { }
|
||||
}
|
||||
@@ -38,11 +38,14 @@ namespace OpenRA.Traits
|
||||
foreach( var rt in world.WorldActor.TraitsImplementing<ResourceType>() )
|
||||
rt.info.PaletteIndex = wr.GetPaletteIndex(rt.info.Palette);
|
||||
|
||||
ShroudRenderer shroud = null;
|
||||
if( world.LocalPlayer != null )
|
||||
shroud = world.LocalPlayer.Shroud;
|
||||
|
||||
for (int x = minx; x < maxx; x++)
|
||||
for (int y = miny; y < maxy; y++)
|
||||
{
|
||||
if (world.LocalPlayer != null &&
|
||||
!world.LocalPlayer.Shroud.IsExplored(new int2(x, y)))
|
||||
if (shroud != null && !shroud.IsExplored(new int2(x, y)))
|
||||
continue;
|
||||
|
||||
var c = content[x, y];
|
||||
@@ -68,7 +71,7 @@ namespace OpenRA.Traits
|
||||
for (int y = map.YOffset; y < map.YOffset + map.Height; y++)
|
||||
{
|
||||
// Todo: Valid terrain should be specified in the resource
|
||||
if (!w.IsCellBuildable(new int2(x,y), false))
|
||||
if (!AllowResourceAt(new int2(x,y)))
|
||||
continue;
|
||||
|
||||
content[x, y].type = resourceTypes.FirstOrDefault(
|
||||
@@ -86,6 +89,14 @@ namespace OpenRA.Traits
|
||||
}
|
||||
}
|
||||
|
||||
public bool AllowResourceAt( int2 a )
|
||||
{
|
||||
if( !world.Map.IsInMap( a.X, a.Y ) ) return false;
|
||||
if( !world.GetTerrainInfo( a ).Buildable ) return false;
|
||||
if( world.WorldActor.Trait<UnitInfluence>().AnyUnitsAt( a ) ) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
Sprite[] ChooseContent(ResourceType t)
|
||||
{
|
||||
return t.info.Sprites[world.SharedRandom.Next(t.info.Sprites.Length)];
|
||||
|
||||
@@ -12,9 +12,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.GameRules;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
@@ -122,19 +119,14 @@ namespace OpenRA.Traits
|
||||
|
||||
public static IEnumerable<int2> GetVisOrigins(Actor a)
|
||||
{
|
||||
if (a.Info.Traits.Contains<BuildingInfo>())
|
||||
var ios = a.TraitOrDefault<IOccupySpace>();
|
||||
if (ios != null)
|
||||
{
|
||||
var bi = a.Info.Traits.Get<BuildingInfo>();
|
||||
return Footprint.Tiles(a.Info.Name, bi, a.Location);
|
||||
}
|
||||
else
|
||||
{
|
||||
var mobile = a.TraitOrDefault<Mobile>();
|
||||
if (mobile != null)
|
||||
return new[] { mobile.fromCell, mobile.toCell };
|
||||
else
|
||||
return new[] { (1f / Game.CellSize * a.CenterLocation).ToInt2() };
|
||||
var cells = ios.OccupiedCells();
|
||||
if (cells.Any()) return cells;
|
||||
}
|
||||
|
||||
return new[] { (1f / Game.CellSize * a.CenterLocation).ToInt2() };
|
||||
}
|
||||
|
||||
void RemoveActor(Actor a)
|
||||
|
||||
@@ -37,6 +37,7 @@ namespace OpenRA.Traits
|
||||
map = world.Map;
|
||||
influence = new InfluenceNode[world.Map.MapSize.X, world.Map.MapSize.Y];
|
||||
|
||||
world.ActorAdded += a => Add( a, a.TraitOrDefault<IOccupySpace>() );
|
||||
world.ActorRemoved += a => Remove( a, a.TraitOrDefault<IOccupySpace>() );
|
||||
}
|
||||
|
||||
@@ -55,8 +56,9 @@ namespace OpenRA.Traits
|
||||
|
||||
public void Add( Actor self, IOccupySpace unit )
|
||||
{
|
||||
foreach( var c in unit.OccupiedCells() )
|
||||
influence[ c.X, c.Y ] = new InfluenceNode { next = influence[ c.X, c.Y ], actor = self };
|
||||
if (unit != null)
|
||||
foreach( var c in unit.OccupiedCells() )
|
||||
influence[ c.X, c.Y ] = new InfluenceNode { next = influence[ c.X, c.Y ], actor = self };
|
||||
}
|
||||
|
||||
public void Remove( Actor self, IOccupySpace unit )
|
||||
@@ -72,7 +74,8 @@ namespace OpenRA.Traits
|
||||
return;
|
||||
else if( influenceNode.actor == toRemove )
|
||||
influenceNode = influenceNode.next;
|
||||
else
|
||||
|
||||
if (influenceNode != null)
|
||||
RemoveInner( ref influenceNode.next, toRemove );
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.GameRules;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Traits;
|
||||
|
||||
@@ -41,7 +40,8 @@ namespace OpenRA
|
||||
|
||||
public void Draw( WorldRenderer wr, World world )
|
||||
{
|
||||
if (Game.Settings.Debug.ShowCollisions)
|
||||
if( world.LocalPlayer == null ) return;
|
||||
if (world.LocalPlayer.PlayerActor.Trait<DeveloperMode>().UnitInfluenceDebug)
|
||||
{
|
||||
var uim = world.WorldActor.Trait<UnitInfluence>();
|
||||
|
||||
@@ -52,67 +52,10 @@ namespace OpenRA
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawBuildingGrid( WorldRenderer wr, World world, string name, BuildingInfo bi )
|
||||
public void DrawGrid( WorldRenderer wr, Dictionary<int2, bool> cells )
|
||||
{
|
||||
var position = Game.viewport.ViewToWorld(Viewport.LastMousePos).ToInt2();
|
||||
var topLeft = position - Footprint.AdjustForBuildingSize( bi );
|
||||
|
||||
// Linebuild for walls.
|
||||
// Assumes a 1x1 footprint; weird things will happen for other footprints
|
||||
if (Rules.Info[name].Traits.Contains<LineBuildInfo>())
|
||||
{
|
||||
foreach (var t in LineBuildUtils.GetLineBuildCells(world, topLeft, name, bi))
|
||||
(world.IsCloseEnoughToBase(world.LocalPlayer, name, bi, t) ? buildOk : buildBlocked)
|
||||
.DrawAt(wr, Game.CellSize * t, "terrain");
|
||||
}
|
||||
else
|
||||
{
|
||||
var res = world.WorldActor.Trait<ResourceLayer>();
|
||||
var isCloseEnough = world.IsCloseEnoughToBase(world.LocalPlayer, name, bi, topLeft);
|
||||
foreach (var t in Footprint.Tiles(name, bi, topLeft))
|
||||
((isCloseEnough && world.IsCellBuildable(t, bi.WaterBound) && res.GetResource(t) == null) ? buildOk : buildBlocked)
|
||||
.DrawAt( wr, Game.CellSize * t, "terrain");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class LineBuildUtils
|
||||
{
|
||||
public static IEnumerable<int2> GetLineBuildCells(World world, int2 location, string name, BuildingInfo bi)
|
||||
{
|
||||
int range = Rules.Info[name].Traits.Get<LineBuildInfo>().Range;
|
||||
var topLeft = location; // 1x1 assumption!
|
||||
|
||||
if (world.IsCellBuildable(topLeft, bi.WaterBound))
|
||||
yield return topLeft;
|
||||
|
||||
// Start at place location, search outwards
|
||||
// TODO: First make it work, then make it nice
|
||||
var vecs = new[] { new int2(1, 0), new int2(0, 1), new int2(-1, 0), new int2(0, -1) };
|
||||
int[] dirs = { 0, 0, 0, 0 };
|
||||
for (int d = 0; d < 4; d++)
|
||||
{
|
||||
for (int i = 1; i < range; i++)
|
||||
{
|
||||
if (dirs[d] != 0)
|
||||
continue;
|
||||
|
||||
int2 cell = topLeft + i * vecs[d];
|
||||
if (world.IsCellBuildable(cell, bi.WaterBound))
|
||||
continue; // Cell is empty; continue search
|
||||
|
||||
// Cell contains an actor. Is it the type we want?
|
||||
if (world.Queries.WithTrait<LineBuild>().Any(a => (a.Actor.Info.Name == name && a.Actor.Location.X == cell.X && a.Actor.Location.Y == cell.Y)))
|
||||
dirs[d] = i; // Cell contains actor of correct type
|
||||
else
|
||||
dirs[d] = -1; // Cell is blocked by another actor type
|
||||
}
|
||||
|
||||
// Place intermediate-line sections
|
||||
if (dirs[d] > 0)
|
||||
for (int i = 1; i < dirs[d]; i++)
|
||||
yield return topLeft + i * vecs[d];
|
||||
}
|
||||
foreach( var c in cells )
|
||||
( c.Value ? buildOk : buildBlocked ).DrawAt( wr, Game.CellSize * c.Key, "terrain" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,9 +46,15 @@ namespace OpenRA.Widgets
|
||||
foreach (var line in recentLines.AsEnumerable().Reverse())
|
||||
{
|
||||
chatpos.Y -= 20;
|
||||
var owner = line.Owner + ":";
|
||||
var inset = Game.Renderer.RegularFont.Measure(owner).X + 10;
|
||||
Game.Renderer.RegularFont.DrawText(owner, chatpos, line.Color);
|
||||
int inset = 0;
|
||||
|
||||
if (!string.IsNullOrEmpty(line.Owner))
|
||||
{
|
||||
var owner = line.Owner + ":";
|
||||
inset = Game.Renderer.RegularFont.Measure(owner).X + 10;
|
||||
Game.Renderer.RegularFont.DrawText(owner, chatpos, line.Color);
|
||||
}
|
||||
|
||||
Game.Renderer.RegularFont.DrawText(line.Text, chatpos + new int2(inset, 0), Color.White);
|
||||
}
|
||||
|
||||
|
||||
11
OpenRA.Game/Widgets/ChatEntryWidget.cs
Normal file → Executable file
11
OpenRA.Game/Widgets/ChatEntryWidget.cs
Normal file → Executable file
@@ -20,7 +20,7 @@ namespace OpenRA.Widgets
|
||||
// this emulates the previous chat support, with one improvement: shift+enter can toggle the
|
||||
// team/all mode *while* composing, not just on beginning to compose.
|
||||
|
||||
class ChatEntryWidget : Widget
|
||||
public class ChatEntryWidget : Widget
|
||||
{
|
||||
string content = "";
|
||||
bool composing = false;
|
||||
@@ -81,7 +81,14 @@ namespace OpenRA.Widgets
|
||||
{
|
||||
TakeFocus(new MouseInput());
|
||||
composing = true;
|
||||
teamChat ^= e.Modifiers.HasModifier(Modifiers.Shift);
|
||||
if (Game.Settings.Game.TeamChatToggle)
|
||||
{
|
||||
teamChat ^= e.Modifiers.HasModifier(Modifiers.Shift);
|
||||
}
|
||||
else
|
||||
{
|
||||
teamChat = e.Modifiers.HasModifier(Modifiers.Shift);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ using OpenRA.Graphics;
|
||||
|
||||
namespace OpenRA.Widgets
|
||||
{
|
||||
class CheckboxWidget : Widget
|
||||
public class CheckboxWidget : Widget
|
||||
{
|
||||
public string Text = "";
|
||||
public int baseLine = 1;
|
||||
|
||||
@@ -14,7 +14,7 @@ using OpenRA.Graphics;
|
||||
|
||||
namespace OpenRA.Widgets
|
||||
{
|
||||
class ColorBlockWidget : Widget
|
||||
public class ColorBlockWidget : Widget
|
||||
{
|
||||
public Func<Color> GetColor;
|
||||
|
||||
|
||||
@@ -33,9 +33,7 @@ namespace OpenRA.Widgets.Delegates
|
||||
settings.Server.ExternalPort = int.Parse(cs.GetWidget<TextFieldWidget>("EXTERNAL_PORT").Text);
|
||||
settings.Save();
|
||||
|
||||
Server.Server.ServerMain(Game.modData, settings, map);
|
||||
|
||||
Game.JoinServer(IPAddress.Loopback.ToString(), settings.Server.ListenPort);
|
||||
Game.CreateAndJoinServer(settings, map);
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
@@ -27,11 +27,9 @@ namespace OpenRA.Widgets.Delegates
|
||||
{
|
||||
public class DeveloperModeDelegate : IWidgetDelegate
|
||||
{
|
||||
readonly World world;
|
||||
[ObjectCreator.UseCtor]
|
||||
public DeveloperModeDelegate( [ObjectCreator.Param] World world )
|
||||
{
|
||||
this.world = world;
|
||||
var devmodeBG = Widget.RootWidget.GetWidget("INGAME_ROOT").GetWidget("DEVELOPERMODE_BG");
|
||||
var devModeButton = Widget.RootWidget.GetWidget<ButtonWidget>("INGAME_DEVELOPERMODE_BUTTON");
|
||||
|
||||
@@ -45,15 +43,15 @@ namespace OpenRA.Widgets.Delegates
|
||||
() => world.LocalPlayer.PlayerActor.Trait<DeveloperMode>().DisableShroud;
|
||||
devmodeBG.GetWidget<CheckboxWidget>("CHECKBOX_SHROUD").OnMouseDown = mi =>
|
||||
{
|
||||
world.IssueOrder(new Order("DevShroud", world.LocalPlayer.PlayerActor));
|
||||
world.IssueOrder(new Order("DevShroud", world.LocalPlayer.PlayerActor, false));
|
||||
return true;
|
||||
};
|
||||
|
||||
devmodeBG.GetWidget<CheckboxWidget>("CHECKBOX_UNITDEBUG").Checked =
|
||||
() => Game.Settings.Debug.ShowCollisions;
|
||||
devmodeBG.GetWidget<CheckboxWidget>("CHECKBOX_UNITDEBUG").Checked =
|
||||
() => world.LocalPlayer.PlayerActor.Trait<DeveloperMode>().UnitInfluenceDebug;
|
||||
devmodeBG.GetWidget("CHECKBOX_UNITDEBUG").OnMouseDown = mi =>
|
||||
{
|
||||
world.IssueOrder(new Order("DevUnitDebug", world.LocalPlayer.PlayerActor));
|
||||
world.IssueOrder(new Order("DevUnitDebug", world.LocalPlayer.PlayerActor, false));
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -61,13 +59,13 @@ namespace OpenRA.Widgets.Delegates
|
||||
() => world.LocalPlayer.PlayerActor.Trait<DeveloperMode>().PathDebug;
|
||||
devmodeBG.GetWidget("CHECKBOX_PATHDEBUG").OnMouseDown = mi =>
|
||||
{
|
||||
world.IssueOrder(new Order("DevPathDebug", world.LocalPlayer.PlayerActor));
|
||||
world.IssueOrder(new Order("DevPathDebug", world.LocalPlayer.PlayerActor, false));
|
||||
return true;
|
||||
};
|
||||
|
||||
devmodeBG.GetWidget<ButtonWidget>("GIVE_CASH").OnMouseUp = mi =>
|
||||
{
|
||||
world.IssueOrder(new Order("DevGiveCash", world.LocalPlayer.PlayerActor));
|
||||
world.IssueOrder(new Order("DevGiveCash", world.LocalPlayer.PlayerActor, false));
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -75,7 +73,7 @@ namespace OpenRA.Widgets.Delegates
|
||||
() => world.LocalPlayer.PlayerActor.Trait<DeveloperMode>().FastBuild;
|
||||
devmodeBG.GetWidget<CheckboxWidget>("INSTANT_BUILD").OnMouseDown = mi =>
|
||||
{
|
||||
world.IssueOrder(new Order("DevFastBuild", world.LocalPlayer.PlayerActor));
|
||||
world.IssueOrder(new Order("DevFastBuild", world.LocalPlayer.PlayerActor, false));
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -83,7 +81,7 @@ namespace OpenRA.Widgets.Delegates
|
||||
() => world.LocalPlayer.PlayerActor.Trait<DeveloperMode>().FastCharge;
|
||||
devmodeBG.GetWidget<CheckboxWidget>("INSTANT_CHARGE").OnMouseDown = mi =>
|
||||
{
|
||||
world.IssueOrder(new Order("DevFastCharge", world.LocalPlayer.PlayerActor));
|
||||
world.IssueOrder(new Order("DevFastCharge", world.LocalPlayer.PlayerActor, false));
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -91,13 +89,13 @@ namespace OpenRA.Widgets.Delegates
|
||||
() => world.LocalPlayer.PlayerActor.Trait<DeveloperMode>().AllTech;
|
||||
devmodeBG.GetWidget<CheckboxWidget>("ENABLE_TECH").OnMouseDown = mi =>
|
||||
{
|
||||
world.IssueOrder(new Order("DevEnableTech", world.LocalPlayer.PlayerActor));
|
||||
world.IssueOrder(new Order("DevEnableTech", world.LocalPlayer.PlayerActor, false));
|
||||
return true;
|
||||
};
|
||||
|
||||
devmodeBG.GetWidget<ButtonWidget>("GIVE_EXPLORATION").OnMouseUp = mi =>
|
||||
{
|
||||
world.IssueOrder(new Order("DevGiveExploration", world.LocalPlayer.PlayerActor));
|
||||
world.IssueOrder(new Order("DevGiveExploration", world.LocalPlayer.PlayerActor, false));
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
@@ -139,7 +139,7 @@ namespace OpenRA.Widgets.Delegates
|
||||
var nextStance = GetNextStance((Stance)Enum.Parse(typeof(Stance), bw.Text));
|
||||
|
||||
world.IssueOrder(new Order("SetStance", world.LocalPlayer.PlayerActor,
|
||||
new int2(p.Index, (int)nextStance)));
|
||||
new int2(p.Index, (int)nextStance), false));
|
||||
|
||||
bw.Text = nextStance.ToString();
|
||||
}
|
||||
|
||||
@@ -19,11 +19,11 @@ namespace OpenRA.Widgets.Delegates
|
||||
{
|
||||
public class LobbyDelegate : IWidgetDelegate
|
||||
{
|
||||
Widget Players, LocalPlayerTemplate, RemotePlayerTemplate, EmptySlotTemplate, EmptySlotTemplateHost;
|
||||
Widget Players, LocalPlayerTemplate, RemotePlayerTemplate, EmptySlotTemplate, EmptySlotTemplateHost, EmptySpectatorSlotTemplateHost;
|
||||
|
||||
Dictionary<string, string> CountryNames;
|
||||
string MapUid;
|
||||
MapStub Map;
|
||||
Map Map;
|
||||
|
||||
public static Color CurrentColorPreview1;
|
||||
public static Color CurrentColorPreview2;
|
||||
@@ -44,6 +44,7 @@ namespace OpenRA.Widgets.Delegates
|
||||
RemotePlayerTemplate = Players.GetWidget("TEMPLATE_REMOTE");
|
||||
EmptySlotTemplate = Players.GetWidget("TEMPLATE_EMPTY");
|
||||
EmptySlotTemplateHost = Players.GetWidget("TEMPLATE_EMPTY_HOST");
|
||||
EmptySpectatorSlotTemplateHost = Players.GetWidget("TEMPLATE_EMPTY_SPECTATOR");
|
||||
|
||||
var mapPreview = lobby.GetWidget<MapPreviewWidget>("LOBBY_MAP_PREVIEW");
|
||||
mapPreview.Map = () => Map;
|
||||
@@ -71,6 +72,7 @@ namespace OpenRA.Widgets.Delegates
|
||||
};
|
||||
|
||||
CountryNames = Rules.Info["world"].Traits.WithInterface<OpenRA.Traits.CountryInfo>().ToDictionary(a => a.Race, a => a.Name);
|
||||
|
||||
CountryNames.Add("random", "Random");
|
||||
|
||||
var mapButton = lobby.GetWidget("CHANGEMAP_BUTTON");
|
||||
@@ -109,6 +111,8 @@ namespace OpenRA.Widgets.Delegates
|
||||
orderManager.IssueOrder(Order.Command("startgame"));
|
||||
return true;
|
||||
};
|
||||
|
||||
// Todo: Only show if the map requirements are met for player slots
|
||||
startGameButton.IsVisible = () => Game.IsHost;
|
||||
|
||||
Game.LobbyInfoChanged += JoinedServer;
|
||||
@@ -179,7 +183,7 @@ namespace OpenRA.Widgets.Delegates
|
||||
{
|
||||
if (MapUid == orderManager.LobbyInfo.GlobalSettings.Map) return;
|
||||
MapUid = orderManager.LobbyInfo.GlobalSettings.Map;
|
||||
Map = Game.modData.AvailableMaps[MapUid];
|
||||
Map = new Map(Game.modData.AvailableMaps[MapUid]);
|
||||
|
||||
var title = Widget.RootWidget.GetWidget<LabelWidget>("LOBBY_TITLE");
|
||||
title.Text = "OpenRA Multiplayer Lobby - " + orderManager.LobbyInfo.GlobalSettings.ServerName;
|
||||
@@ -230,31 +234,60 @@ namespace OpenRA.Widgets.Delegates
|
||||
{
|
||||
if (Game.IsHost)
|
||||
{
|
||||
template = EmptySlotTemplateHost.Clone();
|
||||
var name = template.GetWidget<ButtonWidget>("NAME");
|
||||
name.GetText = () => s.Closed ? "Closed" : (s.Bot == null)? "Open" : "Bot: " + s.Bot;
|
||||
name.OnMouseUp = _ =>
|
||||
if (slot.Spectator)
|
||||
{
|
||||
if (s.Closed)
|
||||
template = EmptySlotTemplateHost.Clone();
|
||||
var name = template.GetWidget<ButtonWidget>("NAME");
|
||||
var btn = template.GetWidget<ButtonWidget>("JOIN");
|
||||
btn.GetText = () => "Spectate in this slot";
|
||||
name.GetText = () => s.Closed ? "Closed" : "Open";
|
||||
name.OnMouseUp = _ =>
|
||||
{
|
||||
s.Bot = null;
|
||||
orderManager.IssueOrder(Order.Command("slot_open " + s.Index));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s.Bot == null)
|
||||
orderManager.IssueOrder(Order.Command("slot_bot {0} HackyAI".F(s.Index)));
|
||||
if (s.Closed)
|
||||
{
|
||||
orderManager.IssueOrder(Order.Command("slot_open " + s.Index));
|
||||
}
|
||||
else
|
||||
{
|
||||
orderManager.IssueOrder(Order.Command("slot_close " + s.Index));
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
template = EmptySlotTemplateHost.Clone();
|
||||
var name = template.GetWidget<ButtonWidget>("NAME");
|
||||
name.GetText = () => s.Closed ? "Closed" : (s.Bot == null) ? "Open" : "Bot: " + s.Bot;
|
||||
name.OnMouseUp = _ =>
|
||||
{
|
||||
if (s.Closed)
|
||||
{
|
||||
s.Bot = null;
|
||||
orderManager.IssueOrder(Order.Command("slot_open " + s.Index));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s.Bot == null && Map.Players[s.MapPlayer].AllowBots)
|
||||
orderManager.IssueOrder(Order.Command("slot_bot {0} HackyAI".F(s.Index)));
|
||||
else
|
||||
orderManager.IssueOrder(Order.Command("slot_close " + s.Index));
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
template = EmptySlotTemplate.Clone();
|
||||
var name = template.GetWidget<LabelWidget>("NAME");
|
||||
name.GetText = () => s.Closed ? "Closed" : "Open";
|
||||
|
||||
if (slot.Spectator)
|
||||
{
|
||||
var btn = template.GetWidget<ButtonWidget>("JOIN");
|
||||
btn.GetText = () => "Spectate in this slot";
|
||||
}
|
||||
}
|
||||
|
||||
var join = template.GetWidget<ButtonWidget>("JOIN");
|
||||
@@ -289,6 +322,9 @@ namespace OpenRA.Widgets.Delegates
|
||||
var color = template.GetWidget<ButtonWidget>("COLOR");
|
||||
color.OnMouseUp = mi =>
|
||||
{
|
||||
if (Map.Players[s.MapPlayer].LockColor)
|
||||
return false;
|
||||
|
||||
var colorChooser = Widget.RootWidget.GetWidget("SERVER_LOBBY").GetWidget("COLOR_CHOOSER");
|
||||
var hueSlider = colorChooser.GetWidget<SliderWidget>("HUE_SLIDER");
|
||||
hueSlider.SetOffset(orderManager.LocalClient.Color1.GetHue()/360f);
|
||||
@@ -311,7 +347,7 @@ namespace OpenRA.Widgets.Delegates
|
||||
colorBlock.GetColor = () => c.Color1;
|
||||
|
||||
var faction = template.GetWidget<ButtonWidget>("FACTION");
|
||||
faction.OnMouseUp = CycleRace;
|
||||
faction.OnMouseUp = mi => CycleRace(mi, s);
|
||||
var factionname = faction.GetWidget<LabelWidget>("FACTIONNAME");
|
||||
factionname.GetText = () => CountryNames[c.Country];
|
||||
var factionflag = faction.GetWidget<ImageWidget>("FACTIONFLAG");
|
||||
@@ -325,6 +361,14 @@ namespace OpenRA.Widgets.Delegates
|
||||
var status = template.GetWidget<CheckboxWidget>("STATUS");
|
||||
status.Checked = () => c.State == Session.ClientState.Ready;
|
||||
status.OnMouseDown = CycleReady;
|
||||
|
||||
Session.Slot slot1 = slot;
|
||||
color.IsVisible = () => !slot1.Spectator;
|
||||
colorBlock.IsVisible = () => !slot1.Spectator;
|
||||
faction.IsVisible = () => !slot1.Spectator;
|
||||
factionname.IsVisible = () => !slot1.Spectator;
|
||||
factionflag.IsVisible = () => !slot1.Spectator;
|
||||
team.IsVisible = () => !slot1.Spectator;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -346,6 +390,15 @@ namespace OpenRA.Widgets.Delegates
|
||||
var status = template.GetWidget<CheckboxWidget>("STATUS");
|
||||
status.Checked = () => c.State == Session.ClientState.Ready;
|
||||
if (c.Index == orderManager.LocalClient.Index) status.OnMouseDown = CycleReady;
|
||||
|
||||
|
||||
Session.Slot slot1 = slot;
|
||||
color.IsVisible = () => !slot1.Spectator;
|
||||
//colorBlock.IsVisible = () => !slot1.Spectator;
|
||||
faction.IsVisible = () => !slot1.Spectator;
|
||||
factionname.IsVisible = () => !slot1.Spectator;
|
||||
factionflag.IsVisible = () => !slot1.Spectator;
|
||||
team.IsVisible = () => !slot1.Spectator;
|
||||
}
|
||||
|
||||
template.Id = "SLOT_{0}".F(s.Index);
|
||||
@@ -360,8 +413,11 @@ namespace OpenRA.Widgets.Delegates
|
||||
}
|
||||
|
||||
bool SpawnPointAvailable(int index) { return (index == 0) || orderManager.LobbyInfo.Clients.All(c => c.SpawnPoint != index); }
|
||||
bool CycleRace(MouseInput mi)
|
||||
bool CycleRace(MouseInput mi, Session.Slot s)
|
||||
{
|
||||
if (Map.Players[s.MapPlayer].LockColor)
|
||||
return false;
|
||||
|
||||
var countries = CountryNames.Select(a => a.Key);
|
||||
|
||||
if (mi.Button == MouseButton.Right)
|
||||
|
||||
@@ -10,13 +10,15 @@
|
||||
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Server;
|
||||
using System.Net;
|
||||
using System.IO;
|
||||
using OpenRA.Network;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OpenRA.Widgets.Delegates
|
||||
{
|
||||
public class MainMenuButtonsDelegate : IWidgetDelegate
|
||||
{
|
||||
static bool FirstInit = true;
|
||||
|
||||
[ObjectCreator.UseCtor]
|
||||
public MainMenuButtonsDelegate( [ObjectCreator.Param] Widget widget )
|
||||
{
|
||||
@@ -32,9 +34,15 @@ namespace OpenRA.Widgets.Delegates
|
||||
if (FileSystem.Exists("VERSION"))
|
||||
{
|
||||
var s = FileSystem.Open("VERSION");
|
||||
version.Text = s.ReadAllText();
|
||||
var versionFileContent = s.ReadAllText();
|
||||
version.Text = versionFileContent;
|
||||
s.Close();
|
||||
MasterServerQuery.OnVersion += v => { if (!string.IsNullOrEmpty(v)) version.Text += "\nLatest: " + v; };
|
||||
|
||||
MasterServerQuery.OnVersion += v =>
|
||||
{
|
||||
if (!string.IsNullOrEmpty(v))
|
||||
version.Text = versionFileContent + "\nLatest: " + v;
|
||||
};
|
||||
MasterServerQuery.GetCurrentVersion(Game.Settings.Server.MasterServer);
|
||||
}
|
||||
else
|
||||
@@ -44,6 +52,37 @@ namespace OpenRA.Widgets.Delegates
|
||||
MasterServerQuery.ClientVersion = version.Text;
|
||||
|
||||
MasterServerQuery.GetMOTD(Game.Settings.Server.MasterServer);
|
||||
|
||||
if (FirstInit)
|
||||
{
|
||||
FirstInit = false;
|
||||
Game.ConnectionStateChanged += orderManager =>
|
||||
{
|
||||
Widget.CloseWindow();
|
||||
switch( orderManager.Connection.ConnectionState )
|
||||
{
|
||||
case ConnectionState.PreConnecting:
|
||||
Widget.OpenWindow("MAINMENU_BG");
|
||||
break;
|
||||
case ConnectionState.Connecting:
|
||||
Widget.OpenWindow( "CONNECTING_BG",
|
||||
new Dictionary<string, object> { { "host", orderManager.Host }, { "port", orderManager.Port } } );
|
||||
break;
|
||||
case ConnectionState.NotConnected:
|
||||
Widget.OpenWindow( "CONNECTION_FAILED_BG",
|
||||
new Dictionary<string, object> { { "host", orderManager.Host }, { "port", orderManager.Port } } );
|
||||
break;
|
||||
case ConnectionState.Connected:
|
||||
var lobby = Widget.OpenWindow( "SERVER_LOBBY", new Dictionary<string, object> { { "orderManager", orderManager } } );
|
||||
lobby.GetWidget<ChatDisplayWidget>("CHAT_DISPLAY").ClearChat();
|
||||
lobby.GetWidget("CHANGEMAP_BUTTON").Visible = true;
|
||||
lobby.GetWidget("LOCKTEAMS_CHECKBOX").Visible = true;
|
||||
lobby.GetWidget("DISCONNECT_BUTTON").Visible = true;
|
||||
//r.GetWidget("INGAME_ROOT").GetWidget<ChatDisplayWidget>("CHAT_DISPLAY").ClearChat();
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ namespace OpenRA.Widgets.Delegates
|
||||
string GenerateModsLabel()
|
||||
{
|
||||
return string.Join("\n", currentServer.Mods.Select(m =>
|
||||
ModData.AllMods.ContainsKey(m) ? string.Format("{0} ({1})", ModData.AllMods[m].Title, ModData.AllMods[m].Version)
|
||||
Mod.AllMods.ContainsKey(m) ? string.Format("{0} ({1})", Mod.AllMods[m].Title, Mod.AllMods[m].Version)
|
||||
: string.Format("Unknown Mod: {0}",m)).ToArray());
|
||||
}
|
||||
|
||||
|
||||
10
OpenRA.Game/Widgets/Delegates/SettingsMenuDelegate.cs
Normal file → Executable file
10
OpenRA.Game/Widgets/Delegates/SettingsMenuDelegate.cs
Normal file → Executable file
@@ -70,7 +70,15 @@ namespace OpenRA.Widgets.Delegates
|
||||
Game.Settings.Game.InverseDragScroll ^= true;
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
var teamChatToggle = general.GetWidget<CheckboxWidget>("TEAMCHAT_TOGGLE");
|
||||
teamChatToggle.Checked = () => Game.Settings.Game.TeamChatToggle;
|
||||
teamChatToggle.OnMouseDown = mi =>
|
||||
{
|
||||
Game.Settings.Game.TeamChatToggle ^= true;
|
||||
return true;
|
||||
};
|
||||
|
||||
// Audio
|
||||
var audio = bg.GetWidget("AUDIO_PANE");
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ using OpenRA.Graphics;
|
||||
|
||||
namespace OpenRA.Widgets
|
||||
{
|
||||
class ListBoxWidget : Widget
|
||||
public class ListBoxWidget : Widget
|
||||
{
|
||||
public readonly string Background = "dialog3";
|
||||
public readonly int ScrollbarWidth = 24;
|
||||
|
||||
@@ -17,14 +17,14 @@ using OpenRA.Graphics;
|
||||
|
||||
namespace OpenRA.Widgets
|
||||
{
|
||||
class MapPreviewWidget : Widget
|
||||
public class MapPreviewWidget : Widget
|
||||
{
|
||||
public int SpawnClickRadius = 50;
|
||||
|
||||
public Func<MapStub> Map = () => null;
|
||||
public Action<int> OnSpawnClick = spawn => {};
|
||||
public Func<Dictionary<int2, Color>> SpawnColors = () => new Dictionary<int2, Color>();
|
||||
static Cache<MapStub,Bitmap> PreviewCache = new Cache<MapStub, Bitmap>(stub => Minimap.RenderMapPreview( new Map( stub.Package )));
|
||||
static Cache<MapStub,Bitmap> PreviewCache = new Cache<MapStub, Bitmap>(stub => Minimap.RenderMapPreview( new Map( stub )));
|
||||
|
||||
public MapPreviewWidget() : base() { }
|
||||
protected MapPreviewWidget(MapPreviewWidget other)
|
||||
|
||||
61
OpenRA.Game/Widgets/PasswordFieldWidget.cs
Normal file
61
OpenRA.Game/Widgets/PasswordFieldWidget.cs
Normal file
@@ -0,0 +1,61 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using OpenRA.Graphics;
|
||||
|
||||
namespace OpenRA.Widgets
|
||||
{
|
||||
public class PasswordFieldWidget : TextFieldWidget
|
||||
{
|
||||
public PasswordFieldWidget()
|
||||
: base()
|
||||
{
|
||||
}
|
||||
|
||||
protected PasswordFieldWidget(PasswordFieldWidget widget)
|
||||
: base(widget)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void DrawInner( WorldRenderer wr )
|
||||
{
|
||||
int margin = 5;
|
||||
var font = (Bold) ? Game.Renderer.BoldFont : Game.Renderer.RegularFont;
|
||||
var cursor = (showCursor && Focused) ? "|" : "";
|
||||
var textSize = font.Measure(new string('*', Text.Length) + "|");
|
||||
var pos = RenderOrigin;
|
||||
|
||||
WidgetUtils.DrawPanel("dialog3",
|
||||
new Rectangle(pos.X, pos.Y, Bounds.Width, Bounds.Height));
|
||||
|
||||
// Inset text by the margin and center vertically
|
||||
var textPos = pos + new int2(margin, (Bounds.Height - textSize.Y) / 2 - VisualHeight);
|
||||
|
||||
// Right align when editing and scissor when the text overflows
|
||||
if (textSize.X > Bounds.Width - 2 * margin)
|
||||
{
|
||||
if (Focused)
|
||||
textPos += new int2(Bounds.Width - 2 * margin - textSize.X, 0);
|
||||
|
||||
Game.Renderer.EnableScissor(pos.X + margin, pos.Y, Bounds.Width - 2 * margin, Bounds.Bottom);
|
||||
}
|
||||
|
||||
font.DrawText(new string('*', Text.Length) + cursor, textPos, Color.White);
|
||||
|
||||
if (textSize.X > Bounds.Width - 2 * margin)
|
||||
Game.Renderer.DisableScissor();
|
||||
}
|
||||
|
||||
public override Widget Clone() { return new PasswordFieldWidget(this); }
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ using OpenRA.Support;
|
||||
|
||||
namespace OpenRA.Widgets
|
||||
{
|
||||
class PerfGraphWidget : Widget
|
||||
public class PerfGraphWidget : Widget
|
||||
{
|
||||
public PerfGraphWidget() : base() { }
|
||||
|
||||
|
||||
@@ -9,15 +9,12 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Drawing;
|
||||
using OpenRA.Graphics;
|
||||
|
||||
namespace OpenRA.Widgets
|
||||
{
|
||||
class ScrollingTextWidget : Widget
|
||||
public class ScrollingTextWidget : Widget
|
||||
{
|
||||
public string Text = "";
|
||||
private string ScrollingText = "";
|
||||
|
||||
@@ -14,7 +14,7 @@ using OpenRA.Graphics;
|
||||
|
||||
namespace OpenRA.Widgets
|
||||
{
|
||||
class TextFieldWidget : Widget
|
||||
public class TextFieldWidget : Widget
|
||||
{
|
||||
public string Text = "";
|
||||
public int MaxLength = 0;
|
||||
@@ -96,8 +96,8 @@ namespace OpenRA.Widgets
|
||||
}
|
||||
}
|
||||
|
||||
int blinkCycle = 10;
|
||||
bool showCursor = true;
|
||||
protected int blinkCycle = 10;
|
||||
protected bool showCursor = true;
|
||||
public override void Tick()
|
||||
{
|
||||
if (--blinkCycle <= 0)
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace OpenRA.Widgets
|
||||
Right = 8
|
||||
}
|
||||
|
||||
class ViewportScrollControllerWidget : Widget
|
||||
public class ViewportScrollControllerWidget : Widget
|
||||
{
|
||||
public int EdgeScrollThreshold = 15;
|
||||
|
||||
|
||||
@@ -11,9 +11,8 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Support;
|
||||
|
||||
using OpenRA.Graphics;
|
||||
|
||||
namespace OpenRA.Widgets
|
||||
{
|
||||
public class VqaPlayerWidget : Widget
|
||||
@@ -31,6 +30,14 @@ namespace OpenRA.Widgets
|
||||
|
||||
public bool Paused { get { return paused; } }
|
||||
|
||||
|
||||
readonly World world;
|
||||
[ObjectCreator.UseCtor]
|
||||
public VqaPlayerWidget( [ObjectCreator.Param] World world )
|
||||
{
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
public bool DrawOverlay = true;
|
||||
public void Load(string filename)
|
||||
{
|
||||
@@ -148,7 +155,7 @@ namespace OpenRA.Widgets
|
||||
Sound.StopVideo();
|
||||
video.Reset();
|
||||
videoSprite.sheet.Texture.SetData(video.FrameData);
|
||||
OnComplete();
|
||||
world.AddFrameEndTask(_ => OnComplete());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
|
||||
@@ -8,17 +8,17 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Orders;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.Graphics;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Orders;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Widgets
|
||||
{
|
||||
class WorldInteractionControllerWidget : Widget
|
||||
public class WorldInteractionControllerWidget : Widget
|
||||
{
|
||||
readonly World world;
|
||||
[ObjectCreator.UseCtor]
|
||||
@@ -98,6 +98,7 @@ namespace OpenRA.Widgets
|
||||
var done = false;
|
||||
foreach (var o in orders)
|
||||
{
|
||||
if (o.Subject.Destroyed) continue;
|
||||
foreach (var v in o.Subject.TraitsImplementing<IOrderVoice>())
|
||||
{
|
||||
if (Sound.PlayVoice(v.VoicePhraseForOrder(o.Subject, o), o.Subject, o.Subject.Owner.Country.Race))
|
||||
@@ -133,45 +134,16 @@ namespace OpenRA.Widgets
|
||||
{
|
||||
world.Selection.DoControlGroup(world, e.KeyName[0] - '0', e.Modifiers);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (e.KeyChar == '\b' || e.KeyChar == (char)127)
|
||||
{
|
||||
GotoNextBase();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (e.KeyChar == 'a')
|
||||
{
|
||||
StartAttackMoveOrder();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool handled = false;
|
||||
|
||||
foreach (var t in world.WorldActor.TraitsImplementing<INotifyKeyPress>())
|
||||
handled = (t.KeyPressed(world.WorldActor, e)) ? true : handled;
|
||||
|
||||
if (handled) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void StartAttackMoveOrder()
|
||||
{
|
||||
if (world.Selection.Actors.Count() > 0)
|
||||
world.OrderGenerator = new GenericSelectTarget(world.Selection.Actors, "AttackMove", "attackmove");
|
||||
}
|
||||
|
||||
public void GotoNextBase()
|
||||
{
|
||||
var bases = world.Queries.OwnedBy[world.LocalPlayer].WithTrait<BaseBuilding>().ToArray();
|
||||
if (!bases.Any()) return;
|
||||
|
||||
var next = bases
|
||||
.Select( b => b.Actor )
|
||||
.SkipWhile(b => world.Selection.Actors.Contains(b))
|
||||
.Skip(1)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (next == null)
|
||||
next = bases.Select(b => b.Actor).First();
|
||||
|
||||
world.Selection.Combine(world, new Actor[] { next }, false, true);
|
||||
Game.viewport.Center(world.Selection.Actors);
|
||||
}
|
||||
|
||||
IEnumerable<Actor> SelectActorsInBox(World world, float2 a, float2 b)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user