Compare commits
331 Commits
playtest-2
...
playtest-2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa84cfb26e | ||
|
|
971287e989 | ||
|
|
deed6c7267 | ||
|
|
f58f460355 | ||
|
|
2c897d4454 | ||
|
|
b4101c03ee | ||
|
|
200e90a590 | ||
|
|
be8f042e49 | ||
|
|
4b1eb993e4 | ||
|
|
f6ce673345 | ||
|
|
08eeec4d99 | ||
|
|
564a4598b9 | ||
|
|
7e25b6e58e | ||
|
|
57f74606f0 | ||
|
|
b44cb9ad57 | ||
|
|
dfd5906d7f | ||
|
|
2e7b5e8712 | ||
|
|
eb8682fd0e | ||
|
|
2d224a207c | ||
|
|
5070a81db4 | ||
|
|
e97dd2ee47 | ||
|
|
da74c6ad23 | ||
|
|
c7f1d08748 | ||
|
|
7850acc6fb | ||
|
|
ec5b9a1150 | ||
|
|
83f67a9d48 | ||
|
|
fb799ad436 | ||
|
|
60186efca6 | ||
|
|
20ab3b6caa | ||
|
|
32db66eb7e | ||
|
|
112844a9f7 | ||
|
|
745df591e0 | ||
|
|
9c7759d131 | ||
|
|
4bb70f11e9 | ||
|
|
ce5ca9dbca | ||
|
|
0b9a984b7a | ||
|
|
45cd6caeec | ||
|
|
4c517c0e59 | ||
|
|
7884cb310b | ||
|
|
306bece709 | ||
|
|
748a055a24 | ||
|
|
240b26a265 | ||
|
|
ac82121460 | ||
|
|
3189a4f457 | ||
|
|
291e7588e1 | ||
|
|
b8e274e0f9 | ||
|
|
e81a1f78a4 | ||
|
|
51c3455ffe | ||
|
|
583fa0aa39 | ||
|
|
f768f8d969 | ||
|
|
0e26f0ce26 | ||
|
|
2a8beca0f8 | ||
|
|
b5813ebff8 | ||
|
|
0f6f36411a | ||
|
|
f798639125 | ||
|
|
6014095ab3 | ||
|
|
52e265557c | ||
|
|
f9f9fbf3e4 | ||
|
|
d559b5cdb7 | ||
|
|
d6733e62d6 | ||
|
|
00a0aac7a3 | ||
|
|
840ade5b78 | ||
|
|
13d3137ae4 | ||
|
|
62c652a645 | ||
|
|
76428cbda2 | ||
|
|
434ea26950 | ||
|
|
9655b34e5f | ||
|
|
e91caa4e7a | ||
|
|
3b0810a096 | ||
|
|
1d81e71bcb | ||
|
|
29ac9a594a | ||
|
|
fb0e399ab9 | ||
|
|
7c5c989eb2 | ||
|
|
41fd19c766 | ||
|
|
b423889c06 | ||
|
|
5f43923b80 | ||
|
|
5470264f00 | ||
|
|
06ed722b7a | ||
|
|
8565b7be0c | ||
|
|
a3861823c9 | ||
|
|
84fd45ad69 | ||
|
|
dd6a431af2 | ||
|
|
fa31fb199f | ||
|
|
fbeb638582 | ||
|
|
1aebd59062 | ||
|
|
7182908728 | ||
|
|
58a92de5a1 | ||
|
|
4ea04f461a | ||
|
|
26c084cfb8 | ||
|
|
ac513557a1 | ||
|
|
db5b5698a7 | ||
|
|
1f61d22489 | ||
|
|
520f602f23 | ||
|
|
8c5c63a4b5 | ||
|
|
a0741ba26b | ||
|
|
9f21d944d1 | ||
|
|
10f9e3e787 | ||
|
|
eff5e409c0 | ||
|
|
f108735f74 | ||
|
|
e62149398b | ||
|
|
d6e831eb07 | ||
|
|
dcf3912d24 | ||
|
|
efad699d4b | ||
|
|
77a35fd132 | ||
|
|
2fe7e10750 | ||
|
|
6f66a19b18 | ||
|
|
2fc88e439d | ||
|
|
b4b05c3f4e | ||
|
|
0ee1d39bac | ||
|
|
c3521a2490 | ||
|
|
cb93955cc5 | ||
|
|
666efc94d1 | ||
|
|
d2a52fd529 | ||
|
|
085685a769 | ||
|
|
034196ddd6 | ||
|
|
3dc16bdbb4 | ||
|
|
f42f39f9c9 | ||
|
|
40235db52e | ||
|
|
810b73e1f0 | ||
|
|
82850cf4fb | ||
|
|
21e597ca2d | ||
|
|
ed8203c896 | ||
|
|
de7668e8ff | ||
|
|
7271dd5248 | ||
|
|
16dd07bab3 | ||
|
|
5cbfc45819 | ||
|
|
6a238ab51a | ||
|
|
4d9c2a30df | ||
|
|
8b18927c67 | ||
|
|
d77563bdb0 | ||
|
|
d0466714c8 | ||
|
|
08c9c1a92f | ||
|
|
ea3943daf4 | ||
|
|
6ac92c45f1 | ||
|
|
96cd0e2259 | ||
|
|
fc5830a687 | ||
|
|
1dfe437641 | ||
|
|
b8eda5a152 | ||
|
|
de8603832f | ||
|
|
f11bcd27cc | ||
|
|
00dc91cf49 | ||
|
|
8b0255e2f7 | ||
|
|
3a2279f378 | ||
|
|
8085bcb232 | ||
|
|
5e6f325df1 | ||
|
|
f892eb629e | ||
|
|
1629958970 | ||
|
|
2079627030 | ||
|
|
2072b78489 | ||
|
|
3d1d4a1aff | ||
|
|
41665f7e95 | ||
|
|
604aae5980 | ||
|
|
ac613f7bea | ||
|
|
46d0a6d00d | ||
|
|
402afc82ca | ||
|
|
1cd59a0892 | ||
|
|
7b7bcf1005 | ||
|
|
be701007df | ||
|
|
fef6285436 | ||
|
|
b3c4afa620 | ||
|
|
8df1813afd | ||
|
|
6a28bcb49a | ||
|
|
730ed8c597 | ||
|
|
7b5be4a0ec | ||
|
|
30fb1250b3 | ||
|
|
a363bf841c | ||
|
|
da5830845b | ||
|
|
23e6eada26 | ||
|
|
490b0801a0 | ||
|
|
49ab704a84 | ||
|
|
4a12b78f14 | ||
|
|
656dbdcd28 | ||
|
|
88398afba6 | ||
|
|
2f74207bf6 | ||
|
|
f4f9abe4d4 | ||
|
|
e50b8ec7dc | ||
|
|
70f92494b2 | ||
|
|
c07fee3b3b | ||
|
|
07b635672e | ||
|
|
edc4c7ab2b | ||
|
|
6edcc36f17 | ||
|
|
3a2a6c231e | ||
|
|
cf26e4aa8a | ||
|
|
8ca1da8828 | ||
|
|
5764bc1c1c | ||
|
|
dba7335594 | ||
|
|
1461309dba | ||
|
|
d7e8388600 | ||
|
|
e79d039aa0 | ||
|
|
3d8b3efb9e | ||
|
|
58367fdeac | ||
|
|
63d54952d0 | ||
|
|
5904563653 | ||
|
|
5d0b750a64 | ||
|
|
43e99631a8 | ||
|
|
8cd6d60839 | ||
|
|
047d012fff | ||
|
|
0064543989 | ||
|
|
b61b7b5431 | ||
|
|
0c319e88c3 | ||
|
|
da384af339 | ||
|
|
f98f3d0b39 | ||
|
|
439c366ba2 | ||
|
|
d93c42e89c | ||
|
|
850d26a628 | ||
|
|
c3e79405f7 | ||
|
|
03b23d88d2 | ||
|
|
d5d6cea84c | ||
|
|
fb173af647 | ||
|
|
a1bc31883b | ||
|
|
52854c77c2 | ||
|
|
8f58e41304 | ||
|
|
25525b4155 | ||
|
|
66cc0bd8ff | ||
|
|
01c6127545 | ||
|
|
2794e1f62d | ||
|
|
83c9e9e6dd | ||
|
|
39742d02bb | ||
|
|
f1b68a5207 | ||
|
|
493631cd90 | ||
|
|
9a1ce6945b | ||
|
|
ccf66cde2f | ||
|
|
233e9326f0 | ||
|
|
ba97c99f98 | ||
|
|
37edd072a6 | ||
|
|
00358e9fe8 | ||
|
|
888710cbc5 | ||
|
|
518e00c78a | ||
|
|
f2a20a182e | ||
|
|
a058eb06b2 | ||
|
|
64a7592fed | ||
|
|
bfb076b9bc | ||
|
|
5292272902 | ||
|
|
1db3ce4b59 | ||
|
|
060d544390 | ||
|
|
b0e3364a77 | ||
|
|
d78dde4db1 | ||
|
|
a94b2df865 | ||
|
|
e4bb788fb9 | ||
|
|
6dcc401342 | ||
|
|
26a7e06b40 | ||
|
|
2ba8120d79 | ||
|
|
b9b045098b | ||
|
|
a0682d80c0 | ||
|
|
1ff39761b7 | ||
|
|
bddd058b38 | ||
|
|
8efb717cf4 | ||
|
|
65ac607d90 | ||
|
|
0af653b101 | ||
|
|
175b07c0ff | ||
|
|
585cba8af8 | ||
|
|
2a7525122e | ||
|
|
7f7c293856 | ||
|
|
fbb117705e | ||
|
|
78dea9eecb | ||
|
|
be9f52e029 | ||
|
|
000dd6de7b | ||
|
|
5e8e4dd9d5 | ||
|
|
b31a35d34b | ||
|
|
414b3a03c3 | ||
|
|
a7f42dcf0c | ||
|
|
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 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -44,6 +44,9 @@ packaging/osx/launcher/OpenRA.xcodeproj/*.mode1v3
|
||||
temp.c
|
||||
temp.o
|
||||
temp.s
|
||||
|
||||
OpenRA.Launcher.Mac/build/
|
||||
OpenRA.Launcher.Mac/OpenRA.xcodeproj/*.pbxuser
|
||||
OpenRA.Launcher.Mac/OpenRA.xcodeproj/*.perspectivev3
|
||||
OpenRA.Launcher.Mac/OpenRA.xcodeproj/*.mode1v3
|
||||
*.config
|
||||
*.resources
|
||||
|
||||
1
AUTHORS
1
AUTHORS
@@ -8,3 +8,4 @@ The OpenRA developers are:
|
||||
* Alli Witheford
|
||||
* Joakim Lindberg
|
||||
* Andrew Riedi
|
||||
* Tim Mylemans
|
||||
|
||||
4
HACKING
4
HACKING
@@ -68,7 +68,7 @@ to flush the renderer (if you want to see anything).
|
||||
UserSettings stores the data loaded from settings.ini (or defaults). Eventually we need to be
|
||||
able to save values changed in game into settings.ini (not yet implemented)
|
||||
|
||||
Bugs: There is a list of known bugs and features at http://red-bull.ijw.co.nz:3690/OpenRA .
|
||||
Bugs: There is a list of known bugs and features at http://bugs.open-ra.org/ .
|
||||
|
||||
We also have a website at http://www.open-ra.org/ .
|
||||
|
||||
@@ -76,7 +76,7 @@ Our IRC channel is #openra on irc.freenode.net .
|
||||
|
||||
As far as using git, get your own repository on github. You probably want to set up the gitbot
|
||||
to spam irc when you make commits (its nice to know). Push your changes into your git
|
||||
repository, and it will/might :P be merged into chrisforbes/OpenRA .
|
||||
repository, and it will/might :P be merged into http://github.com/OpenRA/OpenRA .
|
||||
See http://help.github.com/ for working with GitHub and see http://progit.org/ for working
|
||||
with Git.
|
||||
|
||||
|
||||
7
INSTALL
7
INSTALL
@@ -37,7 +37,11 @@ These need to be copied into the mods/cnc/packages/ directory.
|
||||
If you have a case-sensitive filesystem you must change the filenames to
|
||||
lower case.
|
||||
|
||||
The files can be downloaded from:
|
||||
http://open-ra.org/get-dependency.php?file=ra-packages for the Red Alert files and
|
||||
http://open-ra.org/get-dependency.php?file=cnc-packages for the Command & Conquer files.
|
||||
|
||||
Alternatively:
|
||||
Red Alert and C&C have been released by EA Games as freeware. They can be
|
||||
downloaded from http://www.commandandconquer.com/classic
|
||||
Unfortunately the installer is 16-bit and so won’t run on 64-bit operating
|
||||
@@ -55,8 +59,7 @@ WINDOWS:
|
||||
* .NET Framework >= 3.5-SP1
|
||||
(http://www.microsoft.com/downloads/details.aspx?FamilyID=AB99342F-5D1A-413D-8319-81DA479AB0D7&displaylang=en)
|
||||
* Tao Framework >= 2.1.0
|
||||
(http://sourceforge.net/projects/taoframework/)
|
||||
(required libs: Tao.OpenGL, Tao.Cg, Tao.Platform.Windows)
|
||||
This is now bundled with OpenRA, copy the files in thirdparty/Tao to the game root directory.
|
||||
* OpenAL >= 1.1
|
||||
(http://connect.creativelabs.com/openal/Downloads/oalinst.zip)
|
||||
* Cg Toolkit >= 2.2
|
||||
|
||||
347
Makefile
347
Makefile
@@ -1,7 +1,202 @@
|
||||
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 utility
|
||||
CSC = gmcs
|
||||
CSFLAGS = -nologo -warn:4 -debug:+ -debug:full -optimize- -codepage:utf8 -unsafe
|
||||
DEFINE = DEBUG;TRACE
|
||||
COMMON_LIBS = System.dll System.Core.dll System.Drawing.dll System.Xml.dll
|
||||
PHONY = core tools package all mods clean distclean
|
||||
|
||||
.SUFFIXES:
|
||||
core: game renderers mod_ra mod_cnc
|
||||
tools: editor ralint seqed filex tsbuild utility
|
||||
package: fixheader core editor utility winlaunch
|
||||
mods: mod_ra mod_cnc
|
||||
all: core tools winlaunch
|
||||
clean:
|
||||
@-rm *.exe *.dll *.mdb mods/**/*.dll mods/**/*.mdb *.resources
|
||||
distclean: clean
|
||||
|
||||
#
|
||||
# Core binaries
|
||||
#
|
||||
fileformats_SRCS = $(shell find OpenRA.FileFormats/ -iname '*.cs')
|
||||
fileformats_TARGET = OpenRA.FileFormats.dll
|
||||
#fileformats_DEPS = fixheader
|
||||
fileformats_KIND = library
|
||||
fileformats_LIBS = $(COMMON_LIBS) thirdparty/Tao/Tao.Sdl.dll System.Windows.Forms.dll thirdparty/ICSharpCode.SharpZipLib.dll
|
||||
PROGRAMS = fileformats
|
||||
fileformats: $(fileformats_TARGET)
|
||||
|
||||
game_SRCS = $(shell find OpenRA.Game/ -iname '*.cs')
|
||||
game_TARGET = OpenRA.Game.exe
|
||||
game_KIND = winexe
|
||||
game_DEPS = $(fileformats_TARGET)
|
||||
game_LIBS = $(COMMON_LIBS) System.Windows.Forms.dll $(game_DEPS) \
|
||||
thirdparty/Tao/Tao.OpenAl.dll thirdparty/Tao/Tao.FreeType.dll
|
||||
game_FLAGS = -win32icon:OpenRA.Game/OpenRA.ico
|
||||
PROGRAMS += game
|
||||
game: $(game_TARGET)
|
||||
|
||||
#
|
||||
# Renderer dlls
|
||||
#
|
||||
rcg_SRCS = $(shell find OpenRA.Renderer.Cg/ -iname '*.cs')
|
||||
rcg_TARGET = OpenRA.Renderer.Cg.dll
|
||||
rcg_KIND = library
|
||||
rcg_DEPS = $(fileformats_TARGET) $(game_TARGET)
|
||||
rcg_LIBS = $(COMMON_LIBS) System.Windows.Forms.dll \
|
||||
thirdparty/Tao/Tao.Cg.dll thirdparty/Tao/Tao.OpenGl.dll thirdparty/Tao/Tao.Sdl.dll \
|
||||
$(rcg_DEPS) $(game_TARGET)
|
||||
|
||||
rgl_SRCS = $(shell find OpenRA.Renderer.Gl/ -iname '*.cs')
|
||||
rgl_TARGET = OpenRA.Renderer.Gl.dll
|
||||
rgl_KIND = library
|
||||
rgl_DEPS = $(fileformats_TARGET) $(game_TARGET)
|
||||
rgl_LIBS = $(COMMON_LIBS) System.Windows.Forms.dll \
|
||||
thirdparty/Tao/Tao.Cg.dll thirdparty/Tao/Tao.OpenGl.dll thirdparty/Tao/Tao.Sdl.dll \
|
||||
$(rgl_DEPS) $(game_TARGET)
|
||||
|
||||
rnull_SRCS = $(shell find OpenRA.Renderer.Null/ -iname '*.cs')
|
||||
rnull_TARGET = OpenRA.Renderer.Null.dll
|
||||
rnull_KIND = library
|
||||
rnull_DEPS = $(fileformats_TARGET) $(game_TARGET)
|
||||
rnull_LIBS = $(COMMON_LIBS) System.Windows.Forms.dll \
|
||||
$(rnull_DEPS) $(game_TARGET)
|
||||
PROGRAMS += rcg rgl rnull
|
||||
renderers: $(rcg_TARGET) $(rgl_TARGET) $(rnull_TARGET)
|
||||
|
||||
#
|
||||
# Official Mods
|
||||
#
|
||||
# Red Alert
|
||||
mod_ra_SRCS = $(shell find OpenRA.Mods.RA/ -iname '*.cs')
|
||||
mod_ra_TARGET = mods/ra/OpenRA.Mods.RA.dll
|
||||
mod_ra_KIND = library
|
||||
mod_ra_DEPS = $(fileformats_TARGET) $(game_TARGET)
|
||||
mod_ra_LIBS = $(COMMON_LIBS) $(mod_ra_DEPS)
|
||||
PROGRAMS += mod_ra
|
||||
mod_ra: $(mod_ra_TARGET)
|
||||
# mono RALint.exe ra
|
||||
|
||||
# Command and Conquer
|
||||
mod_cnc_SRCS = $(shell find OpenRA.Mods.Cnc/ -iname '*.cs')
|
||||
mod_cnc_TARGET = mods/cnc/OpenRA.Mods.Cnc.dll
|
||||
mod_cnc_KIND = library
|
||||
mod_cnc_DEPS = $(fileformats_TARGET) $(game_TARGET) $(mod_ra_TARGET)
|
||||
mod_cnc_LIBS = $(COMMON_LIBS) $(mod_cnc_DEPS)
|
||||
PROGRAMS += mod_cnc
|
||||
mod_cnc: $(mod_cnc_TARGET)
|
||||
# mono RALint.exe cnc
|
||||
|
||||
#
|
||||
# Tools
|
||||
#
|
||||
# Sequence editor (defunct)
|
||||
seqed_SRCS = $(shell find SequenceEditor/ -iname '*.cs')
|
||||
seqed_TARGET = SequenceEditor.exe
|
||||
seqed_KIND = winexe
|
||||
seqed_DEPS = $(fileformats_TARGET)
|
||||
seqed_LIBS = $(COMMON_LIBS) System.Windows.Forms.dll $(seqed_DEPS)
|
||||
seqed_EXTRA = -resource:SequenceEditor.Form1.resources
|
||||
PROGRAMS += seqed
|
||||
SequenceEditor.Form1.resources:
|
||||
resgen2 SequenceEditor/Form1.resx SequenceEditor.Form1.resources 1> /dev/null
|
||||
seqed: SequenceEditor.Form1.resources $(seqed_TARGET)
|
||||
|
||||
# Map Editor
|
||||
editor_SRCS = $(shell find OpenRA.Editor/ -iname '*.cs')
|
||||
editor_TARGET = OpenRA.Editor.exe
|
||||
editor_KIND = winexe
|
||||
editor_DEPS = $(fileformats_TARGET) $(game_TARGET)
|
||||
editor_LIBS = $(COMMON_LIBS) System.Windows.Forms.dll System.Data.dll $(editor_DEPS)
|
||||
editor_EXTRA = -resource:OpenRA.Editor.Form1.resources -resource:OpenRA.Editor.MapSelect.resources
|
||||
PROGRAMS += editor
|
||||
OpenRA.Editor.MapSelect.resources:
|
||||
resgen2 OpenRA.Editor/MapSelect.resx OpenRA.Editor.MapSelect.resources 1> /dev/null
|
||||
OpenRA.Editor.Form1.resources:
|
||||
resgen2 OpenRA.Editor/Form1.resx OpenRA.Editor.Form1.resources 1> /dev/null
|
||||
editor: OpenRA.Editor.MapSelect.resources OpenRA.Editor.Form1.resources $(editor_TARGET)
|
||||
|
||||
# Analyses mod yaml for easy to detect errors
|
||||
ralint_SRCS = $(shell find RALint/ -iname '*.cs')
|
||||
ralint_TARGET = RALint.exe
|
||||
ralint_KIND = exe
|
||||
ralint_DEPS = $(fileformats_TARGET) $(game_TARGET)
|
||||
ralint_LIBS = $(COMMON_LIBS) $(ralint_DEPS)
|
||||
PROGRAMS += ralint
|
||||
ralint: $(ralint_TARGET)
|
||||
|
||||
# Extracts files from packages (mixfiles, zips, etc)
|
||||
filex_SRCS = $(shell find FileExtractor/ -iname '*.cs')
|
||||
filex_TARGET = FileExtractor.exe
|
||||
filex_KIND = exe
|
||||
filex_DEPS = $(fileformats_TARGET)
|
||||
filex_LIBS = $(COMMON_LIBS) $(filex_DEPS)
|
||||
PROGRAMS += filex
|
||||
filex: $(filex_TARGET)
|
||||
|
||||
# Builds and exports tilesets from a bitmap
|
||||
tsbuild_SRCS = $(shell find OpenRA.TilesetBuilder/ -iname '*.cs')
|
||||
tsbuild_TARGET = TilesetBuilder.exe
|
||||
tsbuild_KIND = winexe
|
||||
tsbuild_DEPS = $(fileformats_TARGET) $(game_TARGET)
|
||||
tsbuild_LIBS = $(COMMON_LIBS) $(tsbuild_DEPS) System.Windows.Forms.dll
|
||||
tsbuild_EXTRA = -resource:OpenRA.TilesetBuilder.Form1.resources
|
||||
PROGRAMS += tsbuild
|
||||
OpenRA.TilesetBuilder.Form1.resources:
|
||||
resgen2 OpenRA.TilesetBuilder/Form1.resx OpenRA.TilesetBuilder.Form1.resources 1> /dev/null
|
||||
tsbuild: OpenRA.TilesetBuilder.Form1.resources $(tsbuild_TARGET)
|
||||
|
||||
#
|
||||
# Launchers / Utilities
|
||||
#
|
||||
# Patches binary headers to work around a mono bug
|
||||
fixheader: packaging/fixheader.cs
|
||||
@$(CSC) packaging/fixheader.cs $(CSFLAGS) -out:fixheader.exe -t:exe $(COMMON_LIBS:%=-r:%)
|
||||
PHONY += fixheader
|
||||
|
||||
# Backend for the launcher apps - queries game/mod info and applies actions to an install
|
||||
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)
|
||||
PROGRAMS += utility
|
||||
utility: $(utility_TARGET)
|
||||
|
||||
# Windows launcher
|
||||
winlaunch_SRCS = $(shell find OpenRA.Launcher/ -iname '*.cs')
|
||||
winlaunch_TARGET = OpenRA.Launcher.exe
|
||||
winlaunch_KIND = winexe
|
||||
winlaunch_LIBS = $(COMMON_LIBS) System.Windows.Forms.dll
|
||||
winlaunch_EXTRA = -resource:OpenRA.Launcher.Launcher.resources
|
||||
PROGRAMS += winlaunch
|
||||
OpenRA.Launcher.Launcher.resources:
|
||||
resgen2 OpenRA.Launcher/Launcher.resx OpenRA.Launcher.Launcher.resources 1> /dev/null
|
||||
winlaunch: OpenRA.Launcher.Launcher.resources $(winlaunch_TARGET)
|
||||
|
||||
.PHONY: $(PHONY) $(PROGRAMS)
|
||||
|
||||
#
|
||||
# Generate build rules for each target defined above in PROGRAMS
|
||||
#
|
||||
define BUILD_ASSEMBLY
|
||||
|
||||
$$($(1)_TARGET): $$($(1)_SRCS) Makefile $$($(1)_DEPS)
|
||||
@echo CSC $$(@)
|
||||
@$(CSC) $$($(1)_LIBS:%=-r:%) \
|
||||
-out:$$(@) $(CSFLAGS) $$($(1)_FLAGS) \
|
||||
-define:"$(DEFINE)" \
|
||||
-t:"$$($(1)_KIND)" \
|
||||
$$($(1)_EXTRA) \
|
||||
$$($(1)_SRCS)
|
||||
@test -e fixheader.exe && mono fixheader.exe $$(@) || ``
|
||||
endef
|
||||
|
||||
$(foreach prog,$(PROGRAMS),$(eval $(call BUILD_ASSEMBLY,$(prog))))
|
||||
|
||||
|
||||
#
|
||||
# Install / Uninstall for *nix
|
||||
#
|
||||
prefix = /usr/local
|
||||
datarootdir = $(prefix)/share
|
||||
datadir = $(datarootdir)
|
||||
@@ -10,103 +205,14 @@ BIN_INSTALL_DIR = $(DESTDIR)$(bindir)
|
||||
INSTALL_DIR = $(DESTDIR)$(datadir)/openra
|
||||
INSTALL = install
|
||||
INSTALL_PROGRAM = $(INSTALL)
|
||||
|
||||
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
|
||||
|
||||
gl_SRCS = $(shell find OpenRA.Gl/ -iname '*.cs')
|
||||
gl_TARGET = OpenRA.Gl.dll
|
||||
gl_KIND = library
|
||||
gl_DEPS = $(fileformats_TARGET) $(game_TARGET)
|
||||
gl_LIBS = $(COMMON_LIBS) System.Windows.Forms.dll \
|
||||
thirdparty/Tao/Tao.Cg.dll thirdparty/Tao/Tao.OpenGl.dll thirdparty/Tao/Tao.Sdl.dll \
|
||||
$(gl_DEPS) $(game_TARGET)
|
||||
|
||||
game_SRCS = $(shell find OpenRA.Game/ -iname '*.cs')
|
||||
game_TARGET = OpenRA.Game.exe
|
||||
game_KIND = winexe
|
||||
game_DEPS = $(fileformats_TARGET)
|
||||
game_LIBS = $(COMMON_LIBS) System.Windows.Forms.dll $(game_DEPS) \
|
||||
thirdparty/Tao/Tao.OpenAl.dll thirdparty/Tao/Tao.FreeType.dll
|
||||
game_FLAGS = -win32icon:OpenRA.Game/OpenRA.ico
|
||||
|
||||
ra_SRCS = $(shell find OpenRA.Mods.RA/ -iname '*.cs')
|
||||
ra_TARGET = mods/ra/OpenRA.Mods.RA.dll
|
||||
ra_KIND = library
|
||||
ra_DEPS = $(fileformats_TARGET) $(game_TARGET)
|
||||
ra_LIBS = $(COMMON_LIBS) $(ra_DEPS)
|
||||
|
||||
cnc_SRCS = $(shell find OpenRA.Mods.Cnc/ -iname '*.cs')
|
||||
cnc_TARGET = mods/cnc/OpenRA.Mods.Cnc.dll
|
||||
cnc_KIND = library
|
||||
cnc_DEPS = $(fileformats_TARGET) $(game_TARGET) $(ra_TARGET)
|
||||
cnc_LIBS = $(COMMON_LIBS) $(cnc_DEPS)
|
||||
|
||||
seqed_SRCS = $(shell find SequenceEditor/ -iname '*.cs')
|
||||
seqed_TARGET = SequenceEditor.exe
|
||||
seqed_KIND = winexe
|
||||
seqed_DEPS = $(fileformats_TARGET)
|
||||
seqed_LIBS = $(COMMON_LIBS) System.Windows.Forms.dll $(seqed_DEPS)
|
||||
seqed_EXTRA = -resource:SequenceEditor.Form1.resources
|
||||
|
||||
editor_SRCS = $(shell find OpenRA.Editor/ -iname '*.cs')
|
||||
editor_TARGET = OpenRA.Editor.exe
|
||||
editor_KIND = winexe
|
||||
editor_DEPS = $(fileformats_TARGET) $(game_TARGET)
|
||||
editor_LIBS = $(COMMON_LIBS) System.Windows.Forms.dll System.Data.dll $(editor_DEPS)
|
||||
editor_EXTRA = -resource:OpenRA.Editor.Form1.resources -resource:OpenRA.Editor.MapSelect.resources
|
||||
|
||||
ralint_SRCS = $(shell find RALint/ -iname '*.cs')
|
||||
ralint_TARGET = RALint.exe
|
||||
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 = exe
|
||||
filex_DEPS = $(fileformats_TARGET)
|
||||
filex_LIBS = $(COMMON_LIBS) $(filex_DEPS)
|
||||
|
||||
tsbuild_SRCS = $(shell find OpenRA.TilesetBuilder/ -iname '*.cs')
|
||||
tsbuild_TARGET = TilesetBuilder.exe
|
||||
tsbuild_KIND = winexe
|
||||
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 utility
|
||||
|
||||
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 utility
|
||||
|
||||
CORE = fileformats rcg rgl rnull game editor utility winlaunch
|
||||
install: all
|
||||
@-echo "Installing OpenRA to $(INSTALL_DIR)"
|
||||
@$(INSTALL_PROGRAM) -d $(INSTALL_DIR)
|
||||
@$(INSTALL_PROGRAM) $(foreach prog,$(CORE),$($(prog)_TARGET)) $(INSTALL_DIR)
|
||||
|
||||
@$(INSTALL_PROGRAM) -d $(INSTALL_DIR)/mods/cnc
|
||||
@$(INSTALL_PROGRAM) $(cnc_TARGET) $(INSTALL_DIR)/mods/cnc
|
||||
@$(INSTALL_PROGRAM) $(mod_cnc_TARGET) $(INSTALL_DIR)/mods/cnc
|
||||
@-cp $(foreach f,$(shell ls mods/cnc --hide=*.dll),mods/cnc/$(f)) $(INSTALL_DIR)/mods/cnc
|
||||
@cp -r mods/cnc/maps $(INSTALL_DIR)/mods/cnc
|
||||
@cp -r mods/cnc/chrome $(INSTALL_DIR)/mods/cnc
|
||||
@@ -117,7 +223,7 @@ install: all
|
||||
@cp -r mods/cnc/uibits $(INSTALL_DIR)/mods/cnc
|
||||
|
||||
@$(INSTALL_PROGRAM) -d $(INSTALL_DIR)/mods/ra
|
||||
@$(INSTALL_PROGRAM) $(ra_TARGET) $(INSTALL_DIR)/mods/ra
|
||||
@$(INSTALL_PROGRAM) $(mod_ra_TARGET) $(INSTALL_DIR)/mods/ra
|
||||
@-cp $(foreach f,$(shell ls mods/ra --hide=*.dll),mods/ra/$(f)) $(INSTALL_DIR)/mods/ra
|
||||
@cp -r mods/ra/maps $(INSTALL_DIR)/mods/ra
|
||||
@cp -r mods/ra/bits $(INSTALL_DIR)/mods/ra
|
||||
@@ -126,10 +232,10 @@ install: all
|
||||
@cp -r mods/ra/tilesets $(INSTALL_DIR)/mods/ra
|
||||
@cp -r mods/ra/uibits $(INSTALL_DIR)/mods/ra
|
||||
|
||||
@cp -r shaders $(INSTALL_DIR)
|
||||
@cp -r glsl $(INSTALL_DIR)
|
||||
@cp -r cg $(INSTALL_DIR)
|
||||
@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)
|
||||
|
||||
@@ -138,7 +244,7 @@ install: all
|
||||
@echo "mono "$(datadir)"/openra/OpenRA.Game.exe SupportDir=~/.openra \"$$""@\"" >> openra
|
||||
@$(INSTALL_PROGRAM) -d $(BIN_INSTALL_DIR)
|
||||
@$(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?file=ra-packages and"
|
||||
@echo "http://open-ra.org/get-dependency.php?file=cnc-packages"
|
||||
@@ -150,45 +256,4 @@ install: all
|
||||
|
||||
uninstall:
|
||||
@-rm -r $(INSTALL_DIR)
|
||||
@-rm $(DESTDIR)$(bindir)/openra
|
||||
|
||||
mod_ra: $(ra_TARGET) $(ralint_TARGET)
|
||||
mono RALint.exe ra
|
||||
mod_cnc: $(cnc_TARGET) $(ralint_TARGET)
|
||||
mono RALint.exe cnc
|
||||
mods: mod_ra mod_cnc
|
||||
|
||||
OpenRA.Editor.MapSelect.resources:
|
||||
resgen2 OpenRA.Editor/MapSelect.resx OpenRA.Editor.MapSelect.resources 1> /dev/null
|
||||
|
||||
OpenRA.Editor.Form1.resources:
|
||||
resgen2 OpenRA.Editor/Form1.resx OpenRA.Editor.Form1.resources 1> /dev/null
|
||||
editor: OpenRA.Editor.MapSelect.resources OpenRA.Editor.Form1.resources $(editor_TARGET)
|
||||
ralint: $(ralint_TARGET)
|
||||
seqed: SequenceEditor.Form1.resources $(seqed_TARGET)
|
||||
SequenceEditor.Form1.resources:
|
||||
resgen2 SequenceEditor/Form1.resx SequenceEditor.Form1.resources 1> /dev/null
|
||||
filex: $(filex_TARGET)
|
||||
tsbuild: OpenRA.TilesetBuilder.Form1.resources $(tsbuild_TARGET)
|
||||
OpenRA.TilesetBuilder.Form1.resources:
|
||||
resgen2 OpenRA.TilesetBuilder/Form1.resx OpenRA.TilesetBuilder.Form1.resources 1> /dev/null
|
||||
tools: editor ralint seqed filex tsbuild
|
||||
all: game tools
|
||||
|
||||
fixheader: packaging/fixheader.cs
|
||||
@$(CSC) packaging/fixheader.cs $(CSFLAGS) -out:fixheader.exe -t:exe $(COMMON_LIBS:%=-r:%)
|
||||
|
||||
define BUILD_ASSEMBLY
|
||||
|
||||
$$($(1)_TARGET): $$($(1)_SRCS) Makefile $$($(1)_DEPS) fixheader
|
||||
@echo CSC $$(@)
|
||||
@$(CSC) $$($(1)_LIBS:%=-r:%) \
|
||||
-out:$$(@) $(CSFLAGS) $$($(1)_FLAGS) \
|
||||
-define:"$(DEFINE)" \
|
||||
-t:"$$($(1)_KIND)" \
|
||||
$$($(1)_EXTRA) \
|
||||
$$($(1)_SRCS)
|
||||
@mono fixheader.exe $$(@)
|
||||
endef
|
||||
|
||||
$(foreach prog,$(PROGRAMS),$(eval $(call BUILD_ASSEMBLY,$(prog))))
|
||||
@-rm $(DESTDIR)$(bindir)/openra
|
||||
@@ -94,7 +94,7 @@ namespace OpenRA.Editor
|
||||
void PrepareMapResources(Manifest manifest, Map map)
|
||||
{
|
||||
Rules.LoadRules(manifest, map);
|
||||
tileset = Rules.TileSets[map.Theater];
|
||||
tileset = Rules.TileSets[map.Tileset];
|
||||
tileset.LoadTiles();
|
||||
var palette = new Palette(FileSystem.Open(tileset.Palette), true);
|
||||
|
||||
@@ -213,16 +213,18 @@ namespace OpenRA.Editor
|
||||
{
|
||||
rd.width.Value = surface1.Map.MapSize.X;
|
||||
rd.height.Value = surface1.Map.MapSize.Y;
|
||||
rd.cordonLeft.Value = surface1.Map.TopLeft.X;
|
||||
rd.cordonTop.Value = surface1.Map.TopLeft.Y;
|
||||
rd.cordonRight.Value = surface1.Map.BottomRight.X;
|
||||
rd.cordonBottom.Value = surface1.Map.BottomRight.Y;
|
||||
rd.cordonLeft.Value = surface1.Map.Bounds.Left;
|
||||
rd.cordonTop.Value = surface1.Map.Bounds.Top;
|
||||
rd.cordonRight.Value = surface1.Map.Bounds.Right;
|
||||
rd.cordonBottom.Value = surface1.Map.Bounds.Bottom;
|
||||
|
||||
if (DialogResult.OK != rd.ShowDialog())
|
||||
return;
|
||||
|
||||
surface1.Map.TopLeft = new int2((int)rd.cordonLeft.Value, (int)rd.cordonTop.Value);
|
||||
surface1.Map.BottomRight = new int2((int)rd.cordonRight.Value, (int)rd.cordonBottom.Value);
|
||||
surface1.Map.ResizeCordon((int)rd.cordonLeft.Value,
|
||||
(int)rd.cordonTop.Value,
|
||||
(int)rd.cordonRight.Value,
|
||||
(int)rd.cordonBottom.Value);
|
||||
|
||||
if ((int)rd.width.Value != surface1.Map.MapSize.X || (int)rd.height.Value != surface1.Map.MapSize.Y)
|
||||
{
|
||||
|
||||
2
OpenRA.Editor/MapSelect.Designer.cs
generated
2
OpenRA.Editor/MapSelect.Designer.cs
generated
@@ -256,7 +256,7 @@
|
||||
this.lblTheater.Name = "lblTheater";
|
||||
this.lblTheater.Size = new System.Drawing.Size(47, 13);
|
||||
this.lblTheater.TabIndex = 11;
|
||||
this.lblTheater.Text = "Theater:";
|
||||
this.lblTheater.Text = "Tileset:";
|
||||
//
|
||||
// txtAuthor
|
||||
//
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace OpenRA.Editor
|
||||
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;
|
||||
txtTheater.Text = map.Tileset;
|
||||
txtDesc.Text = map.Description;
|
||||
pbMinimap.Image = null;
|
||||
try
|
||||
|
||||
2
OpenRA.Editor/NewMapDialog.Designer.cs
generated
2
OpenRA.Editor/NewMapDialog.Designer.cs
generated
@@ -221,7 +221,7 @@
|
||||
this.label4.Name = "label4";
|
||||
this.label4.Size = new System.Drawing.Size(44, 13);
|
||||
this.label4.TabIndex = 14;
|
||||
this.label4.Text = "Theater";
|
||||
this.label4.Text = "Tileset";
|
||||
//
|
||||
// theater
|
||||
//
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
@@ -13,8 +13,6 @@
|
||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ApplicationIcon>OpenRA.Editor.Icon.ico</ApplicationIcon>
|
||||
<StartupObject>
|
||||
</StartupObject>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
|
||||
@@ -97,9 +97,9 @@ namespace OpenRA.Editor
|
||||
{
|
||||
var ri = info.Traits.Get<RenderSimpleInfo>();
|
||||
string image = null;
|
||||
if (ri.OverrideTheater != null)
|
||||
for (int i = 0; i < ri.OverrideTheater.Length; i++)
|
||||
if (ri.OverrideTheater[i] == tileset.Id)
|
||||
if (ri.OverrideTileset != null)
|
||||
for (int i = 0; i < ri.OverrideTileset.Length; i++)
|
||||
if (ri.OverrideTileset[i] == tileset.Id)
|
||||
image = ri.OverrideImage[i];
|
||||
|
||||
image = image ?? ri.Image ?? info.Name;
|
||||
|
||||
@@ -505,10 +505,10 @@ namespace OpenRA.Editor
|
||||
}
|
||||
|
||||
e.Graphics.DrawRectangle(CordonPen,
|
||||
Map.XOffset * TileSet.TileSize * Zoom + Offset.X,
|
||||
Map.YOffset * TileSet.TileSize * Zoom + Offset.Y,
|
||||
Map.Width * TileSet.TileSize * Zoom,
|
||||
Map.Height * TileSet.TileSize * Zoom);
|
||||
Map.Bounds.Left * TileSet.TileSize * Zoom + Offset.X,
|
||||
Map.Bounds.Top * TileSet.TileSize * Zoom + Offset.Y,
|
||||
Map.Bounds.Width * TileSet.TileSize * Zoom,
|
||||
Map.Bounds.Height * TileSet.TileSize * Zoom);
|
||||
|
||||
foreach (var ar in Map.Actors)
|
||||
DrawActor(e.Graphics, ar.Value.Location(), ActorTemplates[ar.Value.Type],
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,17 +38,18 @@ namespace OpenRA.FileFormats
|
||||
|
||||
static IFolder OpenPackage(string filename)
|
||||
{
|
||||
if (filename.EndsWith(".mix"))
|
||||
return new Package(filename, order++);
|
||||
else if (filename.EndsWith(".zip"))
|
||||
return new CompressedPackage(filename, order++);
|
||||
if (filename.EndsWith(".mix", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new MixFile(filename, order++);
|
||||
else if (filename.EndsWith(".zip", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new ZipFile(filename, order++);
|
||||
else if (filename.EndsWith(".Z", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new InstallShieldPackage(filename, order++);
|
||||
else
|
||||
return new Folder(filename, order++);
|
||||
}
|
||||
|
||||
public static void Mount(string name)
|
||||
{
|
||||
name = name.ToLowerInvariant();
|
||||
var optional = name.StartsWith("~");
|
||||
if (optional) name = name.Substring(1);
|
||||
|
||||
@@ -67,6 +68,16 @@ namespace OpenRA.FileFormats
|
||||
allFiles = new Cache<uint, List<IFolder>>( _ => new List<IFolder>() );
|
||||
}
|
||||
|
||||
public static bool Unmount(IFolder mount)
|
||||
{
|
||||
return (mountedFolders.RemoveAll(f => f == mount) > 0);
|
||||
}
|
||||
|
||||
public static void Mount(IFolder mount)
|
||||
{
|
||||
if (!mountedFolders.Contains(mount)) mountedFolders.Add(mount);
|
||||
}
|
||||
|
||||
public static void LoadFromManifest( Manifest manifest )
|
||||
{
|
||||
UnmountAll();
|
||||
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();
|
||||
reader.ReadChars(NameLength); //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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ namespace OpenRA.FileFormats
|
||||
int Priority { get; }
|
||||
}
|
||||
|
||||
public class Package : IFolder
|
||||
public class MixFile : IFolder
|
||||
{
|
||||
readonly Dictionary<uint, PackageEntry> index;
|
||||
readonly bool isRmix, isEncrypted;
|
||||
@@ -31,7 +31,7 @@ namespace OpenRA.FileFormats
|
||||
readonly Stream s;
|
||||
int priority;
|
||||
|
||||
public Package(string filename, int priority)
|
||||
public MixFile(string filename, int priority)
|
||||
{
|
||||
this.priority = priority;
|
||||
s = FileSystem.Open(filename);
|
||||
@@ -11,40 +11,39 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Packaging;
|
||||
using ICSharpCode.SharpZipLib.Zip;
|
||||
using SZipFile = ICSharpCode.SharpZipLib.Zip.ZipFile;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
public class CompressedPackage : IFolder
|
||||
public class ZipFile : IFolder
|
||||
{
|
||||
readonly uint[] hashes;
|
||||
readonly Stream s;
|
||||
readonly ZipPackage pkg;
|
||||
readonly SZipFile pkg;
|
||||
int priority;
|
||||
|
||||
public CompressedPackage(string filename, int priority)
|
||||
public ZipFile(string filename, int priority)
|
||||
{
|
||||
this.priority = priority;
|
||||
s = FileSystem.Open(filename);
|
||||
pkg = (ZipPackage)ZipPackage.Open(s, FileMode.Open);
|
||||
hashes = pkg.GetParts()
|
||||
.Select(p => PackageEntry.HashFilename(p.Uri.LocalPath)).ToArray();
|
||||
pkg = new SZipFile(File.OpenRead(filename));
|
||||
}
|
||||
|
||||
public Stream GetContent(string filename)
|
||||
{
|
||||
return pkg.GetPart(new Uri(filename)).GetStream(FileMode.Open);
|
||||
return pkg.GetInputStream(pkg.GetEntry(filename));
|
||||
}
|
||||
|
||||
public IEnumerable<uint> AllFileHashes() { return hashes; }
|
||||
public IEnumerable<uint> AllFileHashes()
|
||||
{
|
||||
foreach(ZipEntry entry in pkg)
|
||||
yield return PackageEntry.HashFilename(entry.Name);
|
||||
}
|
||||
|
||||
public bool Exists(string filename)
|
||||
{
|
||||
return hashes.Contains(PackageEntry.HashFilename(filename));
|
||||
return pkg.GetEntry(filename) != null;
|
||||
}
|
||||
|
||||
|
||||
public int Priority
|
||||
{
|
||||
get { return 500 + priority; }
|
||||
@@ -33,7 +33,7 @@ namespace OpenRA.FileFormats.Graphics
|
||||
IIndexBuffer CreateIndexBuffer( int length );
|
||||
ITexture CreateTexture( Bitmap bitmap );
|
||||
ITexture CreateTexture();
|
||||
IShader CreateShader( Stream stream );
|
||||
IShader CreateShader( string name );
|
||||
|
||||
Size WindowSize { get; }
|
||||
|
||||
|
||||
@@ -18,11 +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 string[] LocalRules = new string[0];
|
||||
public string[] LocalAssemblies = new string[0];
|
||||
public readonly string ShellmapUid, LoadScreen;
|
||||
public readonly int TileSize = 24;
|
||||
|
||||
@@ -37,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,13 +17,14 @@ namespace OpenRA.FileFormats
|
||||
{
|
||||
public class MapStub
|
||||
{
|
||||
public IFolder Package { get; protected set; }
|
||||
public IFolder Container { get; protected set; }
|
||||
|
||||
// Yaml map data
|
||||
public string Uid { get; protected set; }
|
||||
[FieldLoader.Load] public bool Selectable;
|
||||
|
||||
[FieldLoader.Load] public string Title;
|
||||
[FieldLoader.Load] public string Type = "Conquest";
|
||||
[FieldLoader.Load] public string Description;
|
||||
[FieldLoader.Load] public string Author;
|
||||
[FieldLoader.Load] public int PlayerCount;
|
||||
@@ -35,17 +36,17 @@ namespace OpenRA.FileFormats
|
||||
|
||||
[FieldLoader.Load] public int2 TopLeft;
|
||||
[FieldLoader.Load] public int2 BottomRight;
|
||||
public int Width { get { return BottomRight.X - TopLeft.X; } }
|
||||
public int Height { get { return BottomRight.Y - TopLeft.Y; } }
|
||||
public Rectangle Bounds;
|
||||
|
||||
public MapStub() {} // Hack for the editor - not used for anything important
|
||||
public MapStub(IFolder package)
|
||||
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();
|
||||
|
||||
Bounds = Rectangle.FromLTRB(TopLeft.X, TopLeft.Y, BottomRight.X, BottomRight.Y);
|
||||
Uid = Container.GetContent("map.uid").ReadAllText();
|
||||
}
|
||||
|
||||
static object LoadWaypoints( MiniYaml y )
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?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>
|
||||
@@ -54,13 +54,15 @@
|
||||
<Reference Include="WindowsBase">
|
||||
<RequiredTargetFramework>3.0</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\thirdparty\ICSharpCode.SharpZipLib.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<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" />
|
||||
@@ -68,8 +70,6 @@
|
||||
<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" />
|
||||
@@ -101,8 +101,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\InstallShieldPackage.cs" />
|
||||
<Compile Include="FileFormats\Blast.cs" />
|
||||
<Compile Include="Filesystem\ZipFile.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.
|
||||
@@ -112,4 +118,7 @@
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
<ItemGroup>
|
||||
<Folder Include="Filesystem\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -72,5 +72,11 @@ namespace OpenRA
|
||||
{
|
||||
return a + ( b - a ) * mul / div;
|
||||
}
|
||||
|
||||
public int2 Clamp(Rectangle r)
|
||||
{
|
||||
return new int2(Math.Min(r.Right, Math.Max(X, r.Left)),
|
||||
Math.Min(r.Bottom, Math.Max(Y, r.Top)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace OpenRA
|
||||
[Sync]
|
||||
public Player Owner;
|
||||
|
||||
IActivity currentActivity;
|
||||
private IActivity currentActivity;
|
||||
public Group Group;
|
||||
|
||||
internal Actor(World world, string name, TypeDictionary initDict )
|
||||
@@ -68,33 +68,16 @@ namespace OpenRA
|
||||
|
||||
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;
|
||||
if (currentActivity == null)
|
||||
foreach (var ni in TraitsImplementing<INotifyIdle>())
|
||||
ni.TickIdle(this);
|
||||
|
||||
if (currentActivity is Idle)
|
||||
{
|
||||
if (!wasIdle)
|
||||
foreach (var ni in TraitsImplementing<INotifyIdle>())
|
||||
ni.Idle(this);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
currentActivity = Util.RunActivity( this, currentActivity );
|
||||
}
|
||||
|
||||
public bool IsIdle
|
||||
{
|
||||
get { return currentActivity == null || currentActivity is Idle; }
|
||||
get { return currentActivity == null; }
|
||||
}
|
||||
|
||||
OpenRA.FileFormats.Lazy<float2> Size;
|
||||
@@ -108,17 +91,10 @@ namespace OpenRA
|
||||
|
||||
public RectangleF GetBounds(bool useAltitude)
|
||||
{
|
||||
var si = Info.Traits.GetOrDefault<SelectableInfo>();
|
||||
|
||||
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;
|
||||
var size = Size.Value;
|
||||
var loc = CenterLocation - 0.5f * size;
|
||||
|
||||
var si = Info.Traits.GetOrDefault<SelectableInfo>();
|
||||
if (si != null && si.Bounds != null && si.Bounds.Length > 2)
|
||||
loc += new float2(si.Bounds[2], si.Bounds[3]);
|
||||
|
||||
@@ -131,7 +107,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 )
|
||||
{
|
||||
@@ -147,7 +130,6 @@ namespace OpenRA
|
||||
currentActivity.Cancel( this );
|
||||
}
|
||||
|
||||
// For pathdebug, et al
|
||||
public IActivity GetCurrentActivity()
|
||||
{
|
||||
return currentActivity;
|
||||
|
||||
@@ -1,46 +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.Collections.Generic;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Effects
|
||||
{
|
||||
public class MoveFlash : IEffect
|
||||
{
|
||||
Animation anim = new Animation("moveflsh");
|
||||
float2 pos;
|
||||
|
||||
|
||||
public MoveFlash( World world, int2 cell )
|
||||
{
|
||||
this.pos = Game.CellSize * (cell + new float2(0.5f, 0.5f));
|
||||
anim.PlayThen( "idle",
|
||||
() => world.AddFrameEndTask(
|
||||
w => w.Remove( this ) ) );
|
||||
}
|
||||
|
||||
public MoveFlash( World world, float2 pos )
|
||||
{
|
||||
this.pos = pos;
|
||||
anim.PlayThen( "idle",
|
||||
() => world.AddFrameEndTask(
|
||||
w => w.Remove( this ) ) );
|
||||
}
|
||||
|
||||
public void Tick( World world ) { anim.Tick(); }
|
||||
|
||||
public IEnumerable<Renderable> Render()
|
||||
{
|
||||
yield return new Renderable(anim.Image, pos - .5f * anim.Image.size, "shadow", (int)pos.Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,7 @@ namespace OpenRA
|
||||
public static Settings Settings;
|
||||
|
||||
internal static OrderManager orderManager;
|
||||
static Server.Server server;
|
||||
|
||||
public static XRandom CosmeticRandom = new XRandom(); // not synced
|
||||
|
||||
@@ -49,7 +50,7 @@ namespace OpenRA
|
||||
viewport.Center(loc);
|
||||
}
|
||||
|
||||
internal static void JoinServer(string host, int port)
|
||||
public static void JoinServer(string host, int port)
|
||||
{
|
||||
if (orderManager != null) orderManager.Dispose();
|
||||
|
||||
@@ -76,8 +77,9 @@ namespace OpenRA
|
||||
ConnectionStateChanged( orderManager );
|
||||
}
|
||||
|
||||
internal static int RenderFrame = 0;
|
||||
internal static int LocalTick { get { return orderManager.LocalFrameNumber; } }
|
||||
public static int RenderFrame = 0;
|
||||
public static int NetFrameNumber { get { return orderManager.NetFrameNumber; } }
|
||||
public static int LocalTick { get { return orderManager.LocalFrameNumber; } }
|
||||
const int NetTickScale = 3; // 120ms net tick for 40ms local tick
|
||||
|
||||
public static event Action<OrderManager> ConnectionStateChanged = _ => { };
|
||||
@@ -167,7 +169,7 @@ namespace OpenRA
|
||||
BeforeGameStart();
|
||||
|
||||
var map = modData.PrepareMap(mapUID);
|
||||
viewport = new Viewport(new int2(Renderer.Resolution), map.TopLeft, map.BottomRight, Renderer);
|
||||
viewport = new Viewport(new int2(Renderer.Resolution), map.Bounds, Renderer);
|
||||
orderManager.world = new World(modData.Manifest, map, orderManager);
|
||||
worldRenderer = new WorldRenderer(orderManager.world);
|
||||
|
||||
@@ -220,138 +222,19 @@ namespace OpenRA
|
||||
Console.WriteLine("Loading mods: {0}",string.Join(",",mods));
|
||||
|
||||
modData = new ModData( mods );
|
||||
|
||||
// when this client is running in dedicated mode ...
|
||||
if (Settings.Server.IsDedicated)
|
||||
{
|
||||
// it may specify a yaml extension file (to add non synced traits)
|
||||
if (!string.IsNullOrEmpty(Settings.Server.ExtensionYaml))
|
||||
{
|
||||
var r = modData.Manifest.LocalRules.ToList();
|
||||
r.Add(Settings.Server.ExtensionYaml);
|
||||
modData.Manifest.LocalRules = r.ToArray();
|
||||
}
|
||||
// and a dll to the assemblies (to add those non synced traits)
|
||||
if (!string.IsNullOrEmpty(Settings.Server.ExtensionDll))
|
||||
{
|
||||
var r = modData.Manifest.LocalAssemblies.ToList();
|
||||
r.Add(Settings.Server.ExtensionDll);
|
||||
modData.Manifest.LocalAssemblies = r.ToArray();
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(Settings.Server.ExtensionClass))
|
||||
Settings.Server.Extension = modData.ObjectCreator.CreateObject<IServerExtension>(Settings.Server.ExtensionClass);
|
||||
}
|
||||
|
||||
Sound.Initialize();
|
||||
PerfHistory.items["render"].hasNormalTick = false;
|
||||
PerfHistory.items["batches"].hasNormalTick = false;
|
||||
PerfHistory.items["text"].hasNormalTick = false;
|
||||
PerfHistory.items["cursor"].hasNormalTick = false;
|
||||
|
||||
|
||||
JoinLocal();
|
||||
StartGame(modData.Manifest.ShellmapUid);
|
||||
|
||||
if (!Settings.Graphics.UseNullRenderer)
|
||||
{
|
||||
JoinLocal();
|
||||
StartGame(modData.Manifest.ShellmapUid);
|
||||
|
||||
Game.ConnectionStateChanged += om =>
|
||||
{
|
||||
Widget.CloseWindow();
|
||||
switch (om.Connection.ConnectionState)
|
||||
{
|
||||
case ConnectionState.PreConnecting:
|
||||
Widget.OpenWindow("MAINMENU_BG");
|
||||
break;
|
||||
case ConnectionState.Connecting:
|
||||
Widget.OpenWindow("CONNECTING_BG",
|
||||
new Dictionary<string, object>
|
||||
{{"host", om.Host}, {"port", om.Port}});
|
||||
break;
|
||||
case ConnectionState.NotConnected:
|
||||
Widget.OpenWindow("CONNECTION_FAILED_BG",
|
||||
new Dictionary<string, object>
|
||||
{{"host", om.Host}, {"port", om.Port}});
|
||||
break;
|
||||
case ConnectionState.Connected:
|
||||
var lobby = Widget.OpenWindow("SERVER_LOBBY",
|
||||
new Dictionary<string, object>
|
||||
{{"orderManager", om}});
|
||||
lobby.GetWidget<ChatDisplayWidget>("CHAT_DISPLAY").ClearChat();
|
||||
lobby.GetWidget("CHANGEMAP_BUTTON").Visible = true;
|
||||
lobby.GetWidget("LOCKTEAMS_CHECKBOX").Visible = true;
|
||||
lobby.GetWidget("DISCONNECT_BUTTON").Visible = true;
|
||||
|
||||
// Inform whoever is willing to hear it that the player is connected to the lobby
|
||||
if (ConnectedToLobby != null)
|
||||
ConnectedToLobby();
|
||||
|
||||
if (Settings.Server.IsDedicated)
|
||||
{
|
||||
// Force spectator as a default
|
||||
Game.orderManager.IssueOrder(Order.Command("spectator"));
|
||||
}
|
||||
|
||||
if (Game.Settings.Server.Extension != null)
|
||||
Game.Settings.Server.Extension.OnLobbyUp();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
modData.WidgetLoader.LoadWidget(new Dictionary<string, object>(), Widget.RootWidget, "PERF_BG");
|
||||
Widget.OpenWindow("MAINMENU_BG");
|
||||
}else
|
||||
{
|
||||
JoinLocal();
|
||||
StartGame(modData.Manifest.ShellmapUid);
|
||||
|
||||
Game.ConnectionStateChanged += om =>
|
||||
{
|
||||
Widget.CloseWindow();
|
||||
switch (om.Connection.ConnectionState)
|
||||
{
|
||||
case ConnectionState.PreConnecting:
|
||||
Widget.OpenWindow("MAINMENU_BG");
|
||||
break;
|
||||
case ConnectionState.Connecting:
|
||||
Widget.OpenWindow("CONNECTING_BG",
|
||||
new Dictionary<string, object> { { "host", om.Host }, { "port", om.Port } });
|
||||
break;
|
||||
case ConnectionState.NotConnected:
|
||||
Widget.OpenWindow("CONNECTION_FAILED_BG",
|
||||
new Dictionary<string, object> { { "host", om.Host }, { "port", om.Port } });
|
||||
break;
|
||||
case ConnectionState.Connected:
|
||||
var lobby = Widget.OpenWindow("SERVER_LOBBY",
|
||||
new Dictionary<string, object> { { "orderManager", om } });
|
||||
|
||||
// Inform whoever is willing to hear it that the player is connected to the lobby
|
||||
if (ConnectedToLobby != null)
|
||||
ConnectedToLobby();
|
||||
|
||||
if (Settings.Server.IsDedicated)
|
||||
{
|
||||
// Force spectator as a default
|
||||
Game.orderManager.IssueOrder(Order.Command("spectator"));
|
||||
}
|
||||
|
||||
if (Game.Settings.Server.Extension != null)
|
||||
Game.Settings.Server.Extension.OnLobbyUp();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
modData.WidgetLoader.LoadWidget(new Dictionary<string, object>(), Widget.RootWidget, "PERF_BG");
|
||||
Widget.OpenWindow("MAINMENU_BG");
|
||||
}
|
||||
|
||||
if (Settings.Server.IsDedicated)
|
||||
{
|
||||
// Auto-host
|
||||
var map = Game.modData.AvailableMaps.FirstOrDefault(m => m.Value.Selectable).Key;
|
||||
Server.Server.ServerMain(Game.modData, Settings, map);
|
||||
Game.JoinServer(IPAddress.Loopback.ToString(), Settings.Server.ListenPort);
|
||||
}
|
||||
// TODO: unhardcode this
|
||||
modData.WidgetLoader.LoadWidget( new Dictionary<string,object>(), Widget.RootWidget, "PERF_BG" );
|
||||
Widget.OpenWindow("MAINMENU_BG");
|
||||
|
||||
Game.orderManager.LastTickTime = Environment.TickCount;
|
||||
}
|
||||
@@ -377,8 +260,8 @@ namespace OpenRA
|
||||
|
||||
public static void Disconnect()
|
||||
{
|
||||
if (IsHost)
|
||||
Server.Server.StopListening();
|
||||
if (IsHost && server != null)
|
||||
server.Shutdown();
|
||||
|
||||
orderManager.Dispose();
|
||||
var shellmap = modData.Manifest.ShellmapUid;
|
||||
@@ -415,9 +298,6 @@ namespace OpenRA
|
||||
|
||||
public static void RejoinLobby(World world)
|
||||
{
|
||||
if (Game.IsHost && Game.Settings.Server.Extension != null)
|
||||
Game.Settings.Server.Extension.OnRejoinLobby(world);
|
||||
|
||||
var map = orderManager.LobbyInfo.GlobalSettings.Map;
|
||||
var host = orderManager.Host;
|
||||
var port = orderManager.Port;
|
||||
@@ -439,12 +319,15 @@ namespace OpenRA
|
||||
ConnectedToLobby = null;
|
||||
};
|
||||
if (isHost)
|
||||
{
|
||||
Server.Server.ServerMain(Game.modData, Settings, map);
|
||||
JoinServer(IPAddress.Loopback.ToString(), Settings.Server.ListenPort);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,10 +28,9 @@ namespace OpenRA
|
||||
public static void LoadRules(Manifest m, Map map)
|
||||
{
|
||||
// Added support to extend the list of rules (add it to m.LocalRules)
|
||||
// Should only be used to add ITraitNoSync traits! (otherwise BOOM)
|
||||
Info = LoadYamlRules(m.Rules.Concat(m.LocalRules).ToArray(), 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));
|
||||
Info = LoadYamlRules(m.Rules, map.Rules, (k, y) => new ActorInfo(k.Key.ToLowerInvariant(), k.Value, y));
|
||||
Weapons = LoadYamlRules(m.Weapons, map.Weapons, (k, _) => new WeaponInfo(k.Key.ToLowerInvariant(), k.Value));
|
||||
Voices = LoadYamlRules(m.Voices, map.Voices, (k, _) => new VoiceInfo(k.Value));
|
||||
Music = LoadYamlRules(m.Music, new List<MiniYamlNode>(), (k, _) => new MusicInfo(k.Key, k.Value));
|
||||
Movies = LoadYamlRules(m.Movies, new List<MiniYamlNode>(), (k, v) => k.Value.Value);
|
||||
|
||||
|
||||
@@ -27,13 +27,6 @@ namespace OpenRA.GameRules
|
||||
public bool AdvertiseOnline = true;
|
||||
public string MasterServer = "http://master.open-ra.org/";
|
||||
public bool AllowCheats = false;
|
||||
public string ExtensionDll = "";
|
||||
public string ExtensionClass = "";
|
||||
|
||||
/* not storeable */
|
||||
public IServerExtension Extension { get; set; }
|
||||
public string ExtensionYaml { get; set; }
|
||||
public bool IsDedicated { get; set; }
|
||||
}
|
||||
|
||||
public class DebugSettings
|
||||
@@ -46,13 +39,11 @@ namespace OpenRA.GameRules
|
||||
|
||||
public class GraphicSettings
|
||||
{
|
||||
public string Renderer = "Gl";
|
||||
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 readonly int2 MinResolution = new int2(800, 600);
|
||||
public readonly string RenderEngine = "OpenRA.Gl.dll";
|
||||
public readonly string NullRenderEngine = "OpenRA.Renderer.Null.dll";
|
||||
public bool UseNullRenderer { get; set; }
|
||||
}
|
||||
|
||||
public class SoundSettings
|
||||
@@ -115,11 +106,6 @@ namespace OpenRA.GameRules
|
||||
{"Debug", Debug}
|
||||
};
|
||||
|
||||
// Should we run in dedicated mode (use the server extension)
|
||||
Server.IsDedicated = args.GetValue("Server.IsDedicated", false);
|
||||
if (Server.IsDedicated)
|
||||
Graphics.UseNullRenderer = args.GetValue("Graphics.UseNullRenderer", false);
|
||||
|
||||
// Override fieldloader to ignore invalid entries
|
||||
var err1 = FieldLoader.UnknownFieldAction;
|
||||
var err2 = FieldLoader.InvalidValueAction;
|
||||
|
||||
@@ -28,12 +28,12 @@ namespace OpenRA.Graphics
|
||||
public static Bitmap TerrainBitmap(Map map, bool actualSize)
|
||||
{
|
||||
var tileset = Rules.TileSets[map.Tileset];
|
||||
var width = map.Width;
|
||||
var height = map.Height;
|
||||
var width = map.Bounds.Width;
|
||||
var height = map.Bounds.Height;
|
||||
|
||||
if (!actualSize)
|
||||
{
|
||||
width = height = Util.NextPowerOf2(Math.Max(map.Width, map.Height));
|
||||
width = height = Util.NextPowerOf2(Math.Max(map.Bounds.Width, map.Bounds.Height));
|
||||
}
|
||||
|
||||
Bitmap terrain = new Bitmap(width, height);
|
||||
@@ -45,11 +45,11 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
int* c = (int*)bitmapData.Scan0;
|
||||
|
||||
for (var x = 0; x < map.Width; x++)
|
||||
for (var y = 0; y < map.Height; y++)
|
||||
for (var x = 0; x < map.Bounds.Width; x++)
|
||||
for (var y = 0; y < map.Bounds.Height; y++)
|
||||
{
|
||||
var mapX = x + map.TopLeft.X;
|
||||
var mapY = y + map.TopLeft.Y;
|
||||
var mapX = x + map.Bounds.Left;
|
||||
var mapY = y + map.Bounds.Top;
|
||||
var type = tileset.GetTerrainType(map.MapTiles[mapX, mapY]);
|
||||
if (!tileset.Terrain.ContainsKey(type))
|
||||
throw new InvalidDataException("Tileset {0} lacks terraintype {1}".F(tileset.Id, type));
|
||||
@@ -75,11 +75,11 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
int* c = (int*)bitmapData.Scan0;
|
||||
|
||||
for (var x = 0; x < map.Width; x++)
|
||||
for (var y = 0; y < map.Height; y++)
|
||||
for (var x = 0; x < map.Bounds.Width; x++)
|
||||
for (var y = 0; y < map.Bounds.Height; y++)
|
||||
{
|
||||
var mapX = x + map.TopLeft.X;
|
||||
var mapY = y + map.TopLeft.Y;
|
||||
var mapX = x + map.Bounds.Left;
|
||||
var mapY = y + map.Bounds.Top;
|
||||
if (map.MapResources[mapX, mapY].type == 0)
|
||||
continue;
|
||||
|
||||
@@ -100,7 +100,7 @@ namespace OpenRA.Graphics
|
||||
public static Bitmap CustomTerrainBitmap(World world)
|
||||
{
|
||||
var map = world.Map;
|
||||
var size = Util.NextPowerOf2(Math.Max(map.Width, map.Height));
|
||||
var size = Util.NextPowerOf2(Math.Max(map.Bounds.Width, map.Bounds.Height));
|
||||
Bitmap bitmap = new Bitmap(size, size);
|
||||
var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
|
||||
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
|
||||
@@ -109,11 +109,11 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
int* c = (int*)bitmapData.Scan0;
|
||||
|
||||
for (var x = 0; x < map.Width; x++)
|
||||
for (var y = 0; y < map.Height; y++)
|
||||
for (var x = 0; x < map.Bounds.Width; x++)
|
||||
for (var y = 0; y < map.Bounds.Height; y++)
|
||||
{
|
||||
var mapX = x + map.TopLeft.X;
|
||||
var mapY = y + map.TopLeft.Y;
|
||||
var mapX = x + map.Bounds.Left;
|
||||
var mapY = y + map.Bounds.Top;
|
||||
var custom = map.CustomTerrain[mapX,mapY];
|
||||
if (custom == null)
|
||||
continue;
|
||||
@@ -127,7 +127,7 @@ namespace OpenRA.Graphics
|
||||
public static Bitmap ActorsBitmap(World world)
|
||||
{
|
||||
var map = world.Map;
|
||||
var size = Util.NextPowerOf2(Math.Max(map.Width, map.Height));
|
||||
var size = Util.NextPowerOf2(Math.Max(map.Bounds.Width, map.Bounds.Height));
|
||||
Bitmap bitmap = new Bitmap(size, size);
|
||||
var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
|
||||
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
|
||||
@@ -136,17 +136,15 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
int* c = (int*)bitmapData.Scan0;
|
||||
|
||||
var player = world.LocalPlayer;
|
||||
|
||||
foreach (var t in world.Queries.WithTraitMultiple<IRadarSignature>())
|
||||
{
|
||||
if (!t.Actor.IsVisible(player))
|
||||
if (!world.LocalShroud.IsVisible(t.Actor))
|
||||
continue;
|
||||
|
||||
var color = t.Trait.RadarSignatureColor(t.Actor);
|
||||
foreach (var cell in t.Trait.RadarSignatureCells(t.Actor))
|
||||
if (world.Map.IsInMap(cell))
|
||||
*(c + ((cell.Y - world.Map.TopLeft.Y) * bitmapData.Stride >> 2) + cell.X - world.Map.TopLeft.X) = color.ToArgb();
|
||||
*(c + ((cell.Y - world.Map.Bounds.Top) * bitmapData.Stride >> 2) + cell.X - world.Map.Bounds.Left) = color.ToArgb();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,28 +155,29 @@ namespace OpenRA.Graphics
|
||||
public static Bitmap ShroudBitmap(World world)
|
||||
{
|
||||
var map = world.Map;
|
||||
var size = Util.NextPowerOf2(Math.Max(map.Width, map.Height));
|
||||
var size = Util.NextPowerOf2(Math.Max(map.Bounds.Width, map.Bounds.Height));
|
||||
Bitmap bitmap = new Bitmap(size, size);
|
||||
if (world.LocalShroud.Disabled)
|
||||
return bitmap;
|
||||
|
||||
var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
|
||||
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
|
||||
|
||||
var shroud = Color.Black.ToArgb();
|
||||
var fog = Color.FromArgb(128, Color.Black).ToArgb();
|
||||
|
||||
var playerShroud = world.LocalPlayer.Shroud;
|
||||
|
||||
unsafe
|
||||
{
|
||||
int* c = (int*)bitmapData.Scan0;
|
||||
|
||||
for (var x = 0; x < map.Width; x++)
|
||||
for (var y = 0; y < map.Height; y++)
|
||||
for (var x = 0; x < map.Bounds.Width; x++)
|
||||
for (var y = 0; y < map.Bounds.Height; y++)
|
||||
{
|
||||
var mapX = x + map.TopLeft.X;
|
||||
var mapY = y + map.TopLeft.Y;
|
||||
if (!playerShroud.IsExplored(mapX, mapY))
|
||||
var mapX = x + map.Bounds.Left;
|
||||
var mapY = y + map.Bounds.Top;
|
||||
if (!world.LocalShroud.IsExplored(mapX, mapY))
|
||||
*(c + (y * bitmapData.Stride >> 2) + x) = shroud;
|
||||
else if (!playerShroud.IsVisible(mapX,mapY))
|
||||
else if (!world.LocalShroud.IsVisible(mapX,mapY))
|
||||
*(c + (y * bitmapData.Stride >> 2) + x) = fog;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,10 +46,10 @@ namespace OpenRA.Graphics
|
||||
|
||||
public Renderer()
|
||||
{
|
||||
SpriteShader = device.CreateShader(FileSystem.Open("shaders/world-shp.fx"));
|
||||
LineShader = device.CreateShader(FileSystem.Open("shaders/line.fx"));
|
||||
RgbaSpriteShader = device.CreateShader(FileSystem.Open("shaders/chrome-rgba.fx"));
|
||||
WorldSpriteShader = device.CreateShader(FileSystem.Open("shaders/chrome-shp.fx"));
|
||||
SpriteShader = device.CreateShader("world-shp");
|
||||
LineShader = device.CreateShader("world-line");
|
||||
RgbaSpriteShader = device.CreateShader("chrome-rgba");
|
||||
WorldSpriteShader = device.CreateShader("chrome-shp");
|
||||
|
||||
SpriteRenderer = new SpriteRenderer( this, SpriteShader );
|
||||
RgbaSpriteRenderer = new SpriteRenderer( this, RgbaSpriteShader );
|
||||
@@ -133,18 +133,14 @@ namespace OpenRA.Graphics
|
||||
internal static void Initialize( OpenRA.FileFormats.Graphics.WindowMode windowMode )
|
||||
{
|
||||
var resolution = GetResolution( windowMode );
|
||||
|
||||
if (Game.Settings.Graphics.UseNullRenderer)
|
||||
device = CreateDevice(Assembly.LoadFile(Path.GetFullPath(Game.Settings.Graphics.NullRenderEngine)), resolution.Width, resolution.Height, windowMode, false);
|
||||
else
|
||||
device = CreateDevice( Assembly.LoadFile( Path.GetFullPath( Game.Settings.Graphics.RenderEngine ) ), resolution.Width, resolution.Height, windowMode, false );
|
||||
device = CreateDevice( Assembly.LoadFile( Path.GetFullPath( "OpenRA.Renderer.{0}.dll".F(Game.Settings.Graphics.Renderer) ) ), resolution.Width, resolution.Height, windowMode, false );
|
||||
}
|
||||
|
||||
static Size GetResolution(WindowMode windowmode)
|
||||
{
|
||||
var desktopResolution = Screen.PrimaryScreen.Bounds.Size;
|
||||
var desktopResolution = Screen.PrimaryScreen.Bounds.Size;
|
||||
var customSize = (windowmode == WindowMode.Windowed) ? Game.Settings.Graphics.WindowedSize : Game.Settings.Graphics.FullscreenSize;
|
||||
|
||||
|
||||
if (customSize.X > 0 && customSize.Y > 0)
|
||||
{
|
||||
desktopResolution.Width = customSize.X;
|
||||
|
||||
@@ -21,15 +21,13 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
static Dictionary<string, Dictionary<string, Sequence>> units;
|
||||
|
||||
public static void Initialize(string[] sequenceFiles)
|
||||
public static void Initialize(string[] sequenceFiles, List<MiniYamlNode> sequenceNodes)
|
||||
{
|
||||
units = new Dictionary<string, Dictionary<string, Sequence>>();
|
||||
if (sequenceFiles.Length == 0)
|
||||
return;
|
||||
|
||||
var sequences = sequenceFiles
|
||||
.Select(s => MiniYaml.FromFile(s))
|
||||
.Aggregate(MiniYaml.Merge);
|
||||
var sequences = sequenceFiles.Select(s => MiniYaml.FromFile(s)).Aggregate(sequenceNodes, MiniYaml.Merge);
|
||||
|
||||
foreach (var s in sequences)
|
||||
LoadSequencesForUnit(s.Key, s.Value);
|
||||
|
||||
161
OpenRA.Game/Graphics/ShroudRenderer.cs
Normal file
161
OpenRA.Game/Graphics/ShroudRenderer.cs
Normal file
@@ -0,0 +1,161 @@
|
||||
#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.Traits;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
public class ShroudRenderer
|
||||
{
|
||||
Traits.Shroud shroud;
|
||||
Sprite[] shadowBits = SpriteSheetBuilder.LoadAllSprites("shadow");
|
||||
Sprite[,] sprites, fogSprites;
|
||||
|
||||
bool dirty = true;
|
||||
Map map;
|
||||
|
||||
public ShroudRenderer(World world)
|
||||
{
|
||||
this.shroud = world.LocalShroud;
|
||||
this.map = world.Map;
|
||||
|
||||
sprites = new Sprite[map.MapSize.X, map.MapSize.Y];
|
||||
fogSprites = new Sprite[map.MapSize.X, map.MapSize.Y];
|
||||
shroud.Dirty += () => dirty = true;
|
||||
}
|
||||
|
||||
static readonly byte[][] SpecialShroudTiles =
|
||||
{
|
||||
new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
|
||||
new byte[] { 32, 32, 25, 25, 19, 19, 20, 20 },
|
||||
new byte[] { 33, 33, 33, 33, 26, 26, 26, 26, 21, 21, 21, 21, 23, 23, 23, 23 },
|
||||
new byte[] { 36, 36, 36, 36, 30, 30, 30, 30 },
|
||||
new byte[] { 34, 16, 34, 16, 34, 16, 34, 16, 27, 22, 27, 22, 27, 22, 27, 22 },
|
||||
new byte[] { 44 },
|
||||
new byte[] { 37, 37, 37, 37, 37, 37, 37, 37, 31, 31, 31, 31, 31, 31, 31, 31 },
|
||||
new byte[] { 40 },
|
||||
new byte[] { 35, 24, 17, 18 },
|
||||
new byte[] { 39, 39, 29, 29 },
|
||||
new byte[] { 45 },
|
||||
new byte[] { 43 },
|
||||
new byte[] { 38, 28 },
|
||||
new byte[] { 42 },
|
||||
new byte[] { 41 },
|
||||
new byte[] { 46 },
|
||||
};
|
||||
|
||||
Sprite ChooseShroud(int i, int j)
|
||||
{
|
||||
if( !shroud.IsExplored( i, j ) ) return shadowBits[ 0xf ];
|
||||
|
||||
// bits are for unexploredness: up, right, down, left
|
||||
var v = 0;
|
||||
// bits are for unexploredness: TL, TR, BR, BL
|
||||
var u = 0;
|
||||
|
||||
if( !shroud.IsExplored( i, j - 1 ) ) { v |= 1; u |= 3; }
|
||||
if( !shroud.IsExplored( i + 1, j ) ) { v |= 2; u |= 6; }
|
||||
if( !shroud.IsExplored( i, j + 1 ) ) { v |= 4; u |= 12; }
|
||||
if( !shroud.IsExplored( i - 1, j ) ) { v |= 8; u |= 9; }
|
||||
|
||||
var uSides = u;
|
||||
|
||||
if( !shroud.IsExplored( i - 1, j - 1 ) ) u |= 1;
|
||||
if( !shroud.IsExplored( i + 1, j - 1 ) ) u |= 2;
|
||||
if( !shroud.IsExplored( i + 1, j + 1 ) ) u |= 4;
|
||||
if( !shroud.IsExplored( i - 1, j + 1 ) ) u |= 8;
|
||||
|
||||
return shadowBits[ SpecialShroudTiles[ u ^ uSides ][ v ] ];
|
||||
}
|
||||
|
||||
Sprite ChooseFog(int i, int j)
|
||||
{
|
||||
if (!shroud.IsVisible(i,j)) return shadowBits[0xf];
|
||||
if (!shroud.IsExplored(i, j)) return shadowBits[0xf];
|
||||
|
||||
// bits are for unexploredness: up, right, down, left
|
||||
var v = 0;
|
||||
// bits are for unexploredness: TL, TR, BR, BL
|
||||
var u = 0;
|
||||
|
||||
if (!shroud.IsVisible(i, j - 1)) { v |= 1; u |= 3; }
|
||||
if (!shroud.IsVisible(i + 1, j)) { v |= 2; u |= 6; }
|
||||
if (!shroud.IsVisible(i, j + 1)) { v |= 4; u |= 12; }
|
||||
if (!shroud.IsVisible(i - 1, j)) { v |= 8; u |= 9; }
|
||||
|
||||
var uSides = u;
|
||||
|
||||
if (!shroud.IsVisible(i - 1, j - 1)) u |= 1;
|
||||
if (!shroud.IsVisible(i + 1, j - 1)) u |= 2;
|
||||
if (!shroud.IsVisible(i + 1, j + 1)) u |= 4;
|
||||
if (!shroud.IsVisible(i - 1, j + 1)) u |= 8;
|
||||
|
||||
return shadowBits[SpecialShroudTiles[u ^ uSides][v]];
|
||||
}
|
||||
|
||||
internal void Draw( WorldRenderer wr )
|
||||
{
|
||||
if (dirty)
|
||||
{
|
||||
dirty = false;
|
||||
for (int i = map.Bounds.Left; i < map.Bounds.Right; i++)
|
||||
for (int j = map.Bounds.Top; j < map.Bounds.Bottom; j++)
|
||||
sprites[i, j] = ChooseShroud(i, j);
|
||||
|
||||
for (int i = map.Bounds.Left; i < map.Bounds.Right; i++)
|
||||
for (int j = map.Bounds.Top; j < map.Bounds.Bottom; j++)
|
||||
fogSprites[i, j] = ChooseFog(i, j);
|
||||
}
|
||||
|
||||
var clipRect = Game.viewport.WorldBounds(wr.world);
|
||||
DrawShroud( wr, clipRect, fogSprites, "fog" );
|
||||
DrawShroud( wr, clipRect, sprites, "shroud" );
|
||||
}
|
||||
|
||||
void DrawShroud( WorldRenderer wr, Rectangle clip, Sprite[,] s, string pal )
|
||||
{
|
||||
var shroudPalette = wr.GetPaletteIndex(pal);
|
||||
|
||||
for (var j = clip.Top; j < clip.Bottom; j++)
|
||||
{
|
||||
var starti = clip.Left;
|
||||
var last = shadowBits[0x0f];
|
||||
for (var i = clip.Left; i < clip.Right; i++)
|
||||
{
|
||||
if ((s[i, j] == shadowBits[0x0f] && last == shadowBits[0x0f])
|
||||
|| (s[i, j] == shadowBits[0] && last == shadowBits[0]))
|
||||
continue;
|
||||
|
||||
if (starti != i)
|
||||
{
|
||||
s[starti, j].DrawAt(
|
||||
Game.CellSize * new float2(starti, j),
|
||||
shroudPalette,
|
||||
new float2(Game.CellSize * (i - starti), Game.CellSize));
|
||||
starti = i + 1;
|
||||
}
|
||||
|
||||
s[i, j].DrawAt(
|
||||
Game.CellSize * new float2(i, j),
|
||||
shroudPalette);
|
||||
starti = i + 1;
|
||||
last = s[i, j];
|
||||
}
|
||||
|
||||
if (starti < clip.Right)
|
||||
s[starti, j].DrawAt(
|
||||
Game.CellSize * new float2(starti, j),
|
||||
shroudPalette,
|
||||
new float2(Game.CellSize * (clip.Right - starti), Game.CellSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -34,15 +34,16 @@ namespace OpenRA.Graphics
|
||||
var tileMapping = new Cache<TileReference<ushort,byte>, Sprite>(
|
||||
x => Game.modData.SheetBuilder.Add(world.TileSet.GetBytes(x), tileSize));
|
||||
|
||||
Vertex[] vertices = new Vertex[4 * map.Height * map.Width];
|
||||
ushort[] indices = new ushort[6 * map.Height * map.Width];
|
||||
Vertex[] vertices = new Vertex[4 * map.Bounds.Height * map.Bounds.Width];
|
||||
ushort[] indices = new ushort[6 * map.Bounds.Height * map.Bounds.Width];
|
||||
|
||||
terrainSheet = tileMapping[map.MapTiles[map.TopLeft.X, map.TopLeft.Y]].sheet;
|
||||
terrainSheet = tileMapping[map.MapTiles[map.Bounds.Left, map.Bounds.Top]].sheet;
|
||||
|
||||
int nv = 0;
|
||||
int ni = 0;
|
||||
for( int j = map.TopLeft.Y ; j < map.BottomRight.Y; j++ )
|
||||
for( int i = map.TopLeft.X ; i < map.BottomRight.X; i++ )
|
||||
|
||||
for( int j = map.Bounds.Top; j < map.Bounds.Bottom; j++ )
|
||||
for( int i = map.Bounds.Left; i < map.Bounds.Right; i++ )
|
||||
{
|
||||
Sprite tile = tileMapping[map.MapTiles[i, j]];
|
||||
// TODO: The zero below should explicitly refer to the terrain palette, but this code is called
|
||||
@@ -64,28 +65,28 @@ namespace OpenRA.Graphics
|
||||
|
||||
public void Draw( WorldRenderer wr, Viewport viewport )
|
||||
{
|
||||
int indicesPerRow = map.Width * 6;
|
||||
int verticesPerRow = map.Width * 4;
|
||||
int indicesPerRow = map.Bounds.Width * 6;
|
||||
int verticesPerRow = map.Bounds.Width * 4;
|
||||
|
||||
int visibleRows = (int)(viewport.Height * 1f / Game.CellSize + 2);
|
||||
|
||||
int firstRow = (int)(viewport.Location.Y * 1f / Game.CellSize - map.YOffset);
|
||||
int firstRow = (int)(viewport.Location.Y * 1f / Game.CellSize - map.Bounds.Top);
|
||||
int lastRow = firstRow + visibleRows;
|
||||
|
||||
if (lastRow < 0 || firstRow > map.Height)
|
||||
if (lastRow < 0 || firstRow > map.Bounds.Height)
|
||||
return;
|
||||
|
||||
if (firstRow < 0) firstRow = 0;
|
||||
if (lastRow > map.Height) lastRow = map.Height;
|
||||
if (lastRow > map.Bounds.Height) lastRow = map.Bounds.Height;
|
||||
|
||||
if (world.LocalPlayer != null && !world.LocalPlayer.Shroud.Disabled && world.LocalPlayer.Shroud.Bounds.HasValue)
|
||||
if (world.LocalPlayer != null && !world.LocalShroud.Disabled && world.LocalShroud.Bounds.HasValue)
|
||||
{
|
||||
var r = world.LocalPlayer.Shroud.Bounds.Value;
|
||||
if (firstRow < r.Top - map.YOffset)
|
||||
firstRow = r.Top - map.YOffset;
|
||||
var r = world.LocalShroud.Bounds.Value;
|
||||
if (firstRow < r.Top - map.Bounds.Top)
|
||||
firstRow = r.Top - map.Bounds.Top;
|
||||
|
||||
if (firstRow > r.Bottom - map.YOffset)
|
||||
firstRow = r.Bottom - map.YOffset;
|
||||
if (firstRow > r.Bottom - map.Bounds.Top)
|
||||
firstRow = r.Bottom - map.Bounds.Top;
|
||||
}
|
||||
|
||||
if( lastRow < firstRow ) lastRow = firstRow;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
@@ -21,8 +22,7 @@ namespace OpenRA.Graphics
|
||||
readonly int2 screenSize;
|
||||
int2 scrollPosition;
|
||||
readonly Renderer renderer;
|
||||
readonly int2 mapStart;
|
||||
readonly int2 mapEnd;
|
||||
readonly Rectangle adjustedMapBounds;
|
||||
|
||||
public float2 Location { get { return scrollPosition; } }
|
||||
|
||||
@@ -52,60 +52,43 @@ namespace OpenRA.Graphics
|
||||
|
||||
private int2 NormalizeScrollPosition(int2 newScrollPosition)
|
||||
{
|
||||
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;
|
||||
if(newScrollPosition.X < topLeftBorder.X - screenSize.X/2)
|
||||
newScrollPosition.X = topLeftBorder.X - screenSize.X/2;
|
||||
if(newScrollPosition.Y > bottomRightBorder.Y - screenSize.Y/2)
|
||||
newScrollPosition.Y = bottomRightBorder.Y - screenSize.Y/2;
|
||||
if(newScrollPosition.X > bottomRightBorder.X - screenSize.X/2)
|
||||
newScrollPosition.X = bottomRightBorder.X - screenSize.X/2;
|
||||
|
||||
return newScrollPosition;
|
||||
return newScrollPosition.Clamp(adjustedMapBounds);
|
||||
}
|
||||
|
||||
public ScrollDirection GetBlockedDirections()
|
||||
{
|
||||
int2 topLeftBorder = (Game.CellSize* mapStart);
|
||||
int2 bottomRightBorder = (Game.CellSize* mapEnd);
|
||||
|
||||
ScrollDirection blockedDirections = ScrollDirection.None;
|
||||
|
||||
if(scrollPosition.Y <= topLeftBorder.Y - screenSize.Y/2)
|
||||
if(scrollPosition.Y <= adjustedMapBounds.Top)
|
||||
blockedDirections = blockedDirections.Set(ScrollDirection.Up, true);
|
||||
if(scrollPosition.X <= topLeftBorder.X - screenSize.X/2)
|
||||
if(scrollPosition.X <= adjustedMapBounds.Left)
|
||||
blockedDirections = blockedDirections.Set(ScrollDirection.Left, true);
|
||||
if(scrollPosition.Y >= bottomRightBorder.Y - screenSize.Y/2)
|
||||
if(scrollPosition.Y >= adjustedMapBounds.Bottom)
|
||||
blockedDirections = blockedDirections.Set(ScrollDirection.Down, true);
|
||||
if(scrollPosition.X >= bottomRightBorder.X - screenSize.X/2)
|
||||
if(scrollPosition.X >= adjustedMapBounds.Right)
|
||||
blockedDirections = blockedDirections.Set(ScrollDirection.Right, true);
|
||||
|
||||
return blockedDirections;
|
||||
}
|
||||
|
||||
public Viewport(int2 screenSize, int2 mapStart, int2 mapEnd, Renderer renderer)
|
||||
public Viewport(int2 screenSize, Rectangle mapBounds, Renderer renderer)
|
||||
{
|
||||
this.screenSize = screenSize;
|
||||
this.renderer = renderer;
|
||||
this.mapStart = mapStart;
|
||||
this.mapEnd = mapEnd;
|
||||
|
||||
this.scrollPosition = Game.CellSize* mapStart;
|
||||
this.adjustedMapBounds = new Rectangle(Game.CellSize*mapBounds.X - screenSize.X/2,
|
||||
Game.CellSize*mapBounds.Y - screenSize.Y/2,
|
||||
Game.CellSize*mapBounds.Width,
|
||||
Game.CellSize*mapBounds.Height);
|
||||
this.scrollPosition = new int2(adjustedMapBounds.Location) + new int2(adjustedMapBounds.Size)/2;
|
||||
}
|
||||
|
||||
public void DrawRegions( WorldRenderer wr, IInputHandler inputHandler )
|
||||
{
|
||||
renderer.BeginFrame(scrollPosition);
|
||||
|
||||
wr.Draw();
|
||||
|
||||
Widget.DoDraw( wr );
|
||||
|
||||
var cursorName = Widget.RootWidget.GetCursorOuter(Viewport.LastMousePos) ?? "default";
|
||||
var c = new Cursor(cursorName);
|
||||
c.Draw(wr, (int)cursorFrame, Viewport.LastMousePos + Location);
|
||||
new Cursor(cursorName).Draw(wr, (int)cursorFrame, Viewport.LastMousePos + Location);
|
||||
|
||||
renderer.EndFrame( inputHandler );
|
||||
}
|
||||
@@ -139,22 +122,38 @@ namespace OpenRA.Graphics
|
||||
|
||||
scrollPosition = this.NormalizeScrollPosition((avgPos.ToInt2() - screenSize / 2));
|
||||
}
|
||||
|
||||
public Rectangle ShroudBounds( World world )
|
||||
{
|
||||
var localPlayer = world.LocalPlayer;
|
||||
if( localPlayer == null ) return world.Map.Bounds;
|
||||
if( localPlayer.Shroud.Disabled ) return world.Map.Bounds;
|
||||
if( !localPlayer.Shroud.Bounds.HasValue ) return world.Map.Bounds;
|
||||
return Rectangle.Intersect( localPlayer.Shroud.Bounds.Value, world.Map.Bounds );
|
||||
}
|
||||
|
||||
public Rectangle ViewBounds()
|
||||
public Rectangle ViewBounds(World world)
|
||||
{
|
||||
int2 boundary = new int2(1,1); // Add a curtain of cells around the viewport to account for rounding errors
|
||||
var tl = ViewToWorld(int2.Zero).ToInt2() - boundary;
|
||||
var br = ViewToWorld(new int2(Width, Height)).ToInt2() + boundary;
|
||||
return Rectangle.FromLTRB(tl.X, tl.Y, br.X, br.Y);
|
||||
var r = WorldBounds(world);
|
||||
var left = (int)(Game.CellSize * r.Left - Game.viewport.Location.X);
|
||||
var top = (int)(Game.CellSize * r.Top - Game.viewport.Location.Y);
|
||||
var right = left + (int)(Game.CellSize * r.Width);
|
||||
var bottom = top + (int)(Game.CellSize * r.Height);
|
||||
|
||||
if (left < 0) left = 0;
|
||||
if (top < 0) top = 0;
|
||||
if (right > Game.viewport.Width) right = Game.viewport.Width;
|
||||
if (bottom > Game.viewport.Height) bottom = Game.viewport.Height;
|
||||
return new Rectangle(left, top, right - left, bottom - top);
|
||||
}
|
||||
|
||||
int2 cachedScroll = new int2(int.MaxValue, int.MaxValue);
|
||||
Rectangle cachedRect;
|
||||
|
||||
public Rectangle WorldBounds(World world)
|
||||
{
|
||||
if (cachedScroll != scrollPosition)
|
||||
{
|
||||
int2 boundary = new int2(1,1); // Add a curtain of cells around the viewport to account for rounding errors
|
||||
var tl = ViewToWorld(int2.Zero).ToInt2() - boundary;
|
||||
var br = ViewToWorld(new int2(Width, Height)).ToInt2() + boundary;
|
||||
cachedRect = Rectangle.Intersect(Rectangle.FromLTRB(tl.X, tl.Y, br.X, br.Y), world.Map.Bounds);
|
||||
cachedScroll = scrollPosition;
|
||||
}
|
||||
|
||||
var b = world.LocalShroud.Bounds;
|
||||
return (b.HasValue) ? Rectangle.Intersect(cachedRect, b.Value) : cachedRect;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,8 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
public readonly World world;
|
||||
internal readonly TerrainRenderer terrainRenderer;
|
||||
internal readonly ShroudRenderer shroudRenderer;
|
||||
|
||||
public readonly UiOverlay uiOverlay;
|
||||
internal readonly HardwarePalette palette;
|
||||
|
||||
@@ -29,6 +31,7 @@ namespace OpenRA.Graphics
|
||||
this.world = world;
|
||||
|
||||
terrainRenderer = new TerrainRenderer(world, this);
|
||||
shroudRenderer = new ShroudRenderer(world);
|
||||
uiOverlay = new UiOverlay();
|
||||
palette = new HardwarePalette(world.Map);
|
||||
|
||||
@@ -48,31 +51,9 @@ namespace OpenRA.Graphics
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle GetBoundsRect()
|
||||
{
|
||||
if (world.LocalPlayer != null && !world.LocalPlayer.Shroud.Disabled && world.LocalPlayer.Shroud.Bounds.HasValue)
|
||||
{
|
||||
var r = world.LocalPlayer.Shroud.Bounds.Value;
|
||||
|
||||
var left = (int)(Game.CellSize * r.Left - Game.viewport.Location.X);
|
||||
var top = (int)(Game.CellSize * r.Top - Game.viewport.Location.Y);
|
||||
var right = left + (int)(Game.CellSize * r.Width);
|
||||
var bottom = top + (int)(Game.CellSize * r.Height);
|
||||
|
||||
if (left < 0) left = 0;
|
||||
if (top < 0) top = 0;
|
||||
if (right > Game.viewport.Width) right = Game.viewport.Width;
|
||||
if (bottom > Game.viewport.Height) bottom = Game.viewport.Height;
|
||||
|
||||
return new Rectangle(left, top, right - left, bottom - top);
|
||||
}
|
||||
else
|
||||
return new Rectangle(0, 0, Game.viewport.Width, Game.viewport.Height);
|
||||
}
|
||||
|
||||
IEnumerable<Renderable> SpritesToRender()
|
||||
{
|
||||
var bounds = GetBoundsRect();
|
||||
var bounds = Game.viewport.ViewBounds(world);
|
||||
var comparer = new SpriteComparer();
|
||||
|
||||
bounds.Offset((int)Game.viewport.Location.X, (int)Game.viewport.Location.Y);
|
||||
@@ -92,7 +73,7 @@ namespace OpenRA.Graphics
|
||||
public void Draw()
|
||||
{
|
||||
RefreshPalette();
|
||||
var bounds = GetBoundsRect();
|
||||
var bounds = Game.viewport.ViewBounds(world);
|
||||
Game.Renderer.EnableScissor(bounds.Left, bounds.Top, bounds.Width, bounds.Height);
|
||||
|
||||
terrainRenderer.Draw(this, Game.viewport);
|
||||
@@ -113,10 +94,15 @@ namespace OpenRA.Graphics
|
||||
if (world.OrderGenerator != null)
|
||||
world.OrderGenerator.RenderAfterWorld(this, world);
|
||||
|
||||
if (world.LocalPlayer != null)
|
||||
world.LocalPlayer.Shroud.Draw( this );
|
||||
|
||||
shroudRenderer.Draw( this );
|
||||
Game.Renderer.DisableScissor();
|
||||
|
||||
foreach (var a in world.Selection.Actors)
|
||||
if (!a.Destroyed)
|
||||
foreach (var t in a.TraitsImplementing<IPostRenderSelection>())
|
||||
t.RenderAfterWorld(this, a);
|
||||
|
||||
Game.Renderer.Flush();
|
||||
}
|
||||
|
||||
void DrawBox(RectangleF r, Color color)
|
||||
@@ -130,20 +116,6 @@ namespace OpenRA.Graphics
|
||||
Game.Renderer.LineRenderer.DrawLine(a, a + c, color, color);
|
||||
}
|
||||
|
||||
void DrawBins(RectangleF bounds)
|
||||
{
|
||||
DrawBox(bounds, Color.Red);
|
||||
if (world.LocalPlayer != null)
|
||||
DrawBox(world.LocalPlayer.Shroud.Bounds.Value, Color.Blue);
|
||||
|
||||
for (var j = 0; j < world.Map.MapSize.Y;
|
||||
j += world.WorldActor.Info.Traits.Get<SpatialBinsInfo>().BinSize)
|
||||
{
|
||||
Game.Renderer.LineRenderer.DrawLine(new float2(0, j * Game.CellSize), new float2(world.Map.MapSize.X * Game.CellSize, j * Game.CellSize), Color.Black, Color.Black);
|
||||
Game.Renderer.LineRenderer.DrawLine(new float2(j * Game.CellSize, 0), new float2(j * Game.CellSize, world.Map.MapSize.Y * Game.CellSize), Color.Black, Color.Black);
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawSelectionBox(Actor selectedUnit, Color c)
|
||||
{
|
||||
var bounds = selectedUnit.GetBounds(true);
|
||||
@@ -184,7 +156,7 @@ namespace OpenRA.Graphics
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawRangeCircle(Color c, float2 location, int range)
|
||||
public void DrawRangeCircle(Color c, float2 location, float range)
|
||||
{
|
||||
var prev = location + Game.CellSize * range * float2.FromAngle(0);
|
||||
for (var i = 1; i <= 32; i++)
|
||||
|
||||
63
OpenRA.Game/Map.cs
Executable file → Normal file
63
OpenRA.Game/Map.cs
Executable file → Normal file
@@ -27,25 +27,27 @@ namespace OpenRA
|
||||
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>();
|
||||
|
||||
// Rules overrides
|
||||
|
||||
// Rules overrides
|
||||
public List<MiniYamlNode> Rules = new List<MiniYamlNode>();
|
||||
|
||||
// Sequences overrides
|
||||
public List<MiniYamlNode> Sequences = new List<MiniYamlNode>();
|
||||
|
||||
// Weapon overrides
|
||||
public List<MiniYamlNode> Weapons = new List<MiniYamlNode>();
|
||||
|
||||
// Voices overrides
|
||||
public List<MiniYamlNode> Voices = new List<MiniYamlNode>();
|
||||
|
||||
// Binary map data
|
||||
public byte TileFormat = 1;
|
||||
[FieldLoader.Load] public int2 MapSize;
|
||||
|
||||
|
||||
public TileReference<ushort, byte>[,] MapTiles;
|
||||
public TileReference<byte, byte>[,] MapResources;
|
||||
public string [,] CustomTerrain;
|
||||
|
||||
// Temporary compat hacks
|
||||
public int XOffset { get { return TopLeft.X; } }
|
||||
public int YOffset { get { return TopLeft.Y; } }
|
||||
public string Theater { get { return Tileset; } }
|
||||
public Rectangle Bounds { get { return Rectangle.FromLTRB(TopLeft.X, TopLeft.Y, BottomRight.X, BottomRight.Y); } }
|
||||
|
||||
public Map()
|
||||
{
|
||||
// Do nothing; not a valid map (editor hack)
|
||||
@@ -65,8 +67,7 @@ namespace OpenRA
|
||||
index = (byte)(tile.Value.PickAny ? 0xffu : 0) } } };
|
||||
|
||||
PlayerCount = 0;
|
||||
TopLeft = new int2(0, 0);
|
||||
BottomRight = new int2(0, 0);
|
||||
ResizeCordon(0,0,0,0);
|
||||
|
||||
Title = "Name your map here";
|
||||
Description = "Describe your map here";
|
||||
@@ -80,11 +81,12 @@ namespace OpenRA
|
||||
public int2 Location = int2.Zero;
|
||||
public string Owner = null;
|
||||
}
|
||||
|
||||
|
||||
public Map(MapStub stub) : this(stub.Container) {}
|
||||
public Map(IFolder package)
|
||||
: base(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 );
|
||||
@@ -177,6 +179,15 @@ namespace OpenRA
|
||||
// Rules
|
||||
Rules = yaml.NodesDict["Rules"].Nodes;
|
||||
|
||||
// Sequences
|
||||
Sequences = (yaml.NodesDict.ContainsKey("Sequences")) ? yaml.NodesDict["Sequences"].Nodes : new List<MiniYamlNode>();
|
||||
|
||||
// Weapons
|
||||
Weapons = (yaml.NodesDict.ContainsKey("Weapons")) ? yaml.NodesDict["Weapons"].Nodes : new List<MiniYamlNode>();
|
||||
|
||||
// Voices
|
||||
Voices = (yaml.NodesDict.ContainsKey("Voices")) ? yaml.NodesDict["Voices"].Nodes : new List<MiniYamlNode>();
|
||||
|
||||
CustomTerrain = new string[MapSize.X, MapSize.Y];
|
||||
LoadBinaryData();
|
||||
}
|
||||
@@ -184,7 +195,7 @@ namespace OpenRA
|
||||
public void Save(string filepath)
|
||||
{
|
||||
// Todo: save to a zip file in the support dir by default
|
||||
Package = new Folder(filepath, 0);
|
||||
Container = new Folder(filepath, 0);
|
||||
MapFormat = 3;
|
||||
|
||||
var root = new List<MiniYamlNode>();
|
||||
@@ -205,9 +216,12 @@ namespace OpenRA
|
||||
x.Key,
|
||||
x.Value.Save() ) ).ToList() ) );
|
||||
|
||||
root.Add( new MiniYamlNode( "Waypoints", MiniYaml.FromDictionary<string, int2>( Waypoints ) ) );
|
||||
root.Add( new MiniYamlNode( "Smudges", MiniYaml.FromList<SmudgeReference>( Smudges ) ) );
|
||||
root.Add( new MiniYamlNode( "Rules", null, Rules ) );
|
||||
root.Add(new MiniYamlNode("Waypoints", MiniYaml.FromDictionary<string, int2>( Waypoints )));
|
||||
root.Add(new MiniYamlNode("Smudges", MiniYaml.FromList<SmudgeReference>( Smudges )));
|
||||
root.Add(new MiniYamlNode("Rules", null, Rules));
|
||||
root.Add(new MiniYamlNode("Sequences", null, Sequences));
|
||||
root.Add(new MiniYamlNode("Weapons", null, Weapons));
|
||||
root.Add(new MiniYamlNode("Voices", null, Voices));
|
||||
|
||||
SaveBinaryData(Path.Combine(filepath, "map.bin"));
|
||||
root.WriteToFile(Path.Combine(filepath, "map.yaml"));
|
||||
@@ -232,7 +246,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");
|
||||
@@ -298,8 +312,8 @@ namespace OpenRA
|
||||
{
|
||||
// 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())
|
||||
@@ -315,7 +329,7 @@ namespace OpenRA
|
||||
|
||||
public bool IsInMap(int x, int y)
|
||||
{
|
||||
return (x >= TopLeft.X && y >= TopLeft.Y && x < BottomRight.X && y < BottomRight.Y);
|
||||
return Bounds.Contains(x,y);
|
||||
}
|
||||
|
||||
static T[,] ResizeArray<T>(T[,] ts, T t, int width, int height)
|
||||
@@ -334,5 +348,12 @@ namespace OpenRA
|
||||
MapResources = ResizeArray(MapResources, MapResources[0, 0], width, height);
|
||||
MapSize = new int2(width, height);
|
||||
}
|
||||
|
||||
public void ResizeCordon(int left, int top, int right, int bottom)
|
||||
{
|
||||
TopLeft = new int2(left, top);
|
||||
BottomRight = new int2(right, bottom);
|
||||
Bounds = Rectangle.FromLTRB(TopLeft.X, TopLeft.Y, BottomRight.X, BottomRight.Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,12 +20,12 @@ namespace OpenRA
|
||||
{
|
||||
public readonly Manifest Manifest;
|
||||
public readonly ObjectCreator ObjectCreator;
|
||||
public readonly SheetBuilder SheetBuilder;
|
||||
public readonly CursorSheetBuilder CursorSheetBuilder;
|
||||
public readonly Dictionary<string, MapStub> AvailableMaps;
|
||||
public readonly WidgetLoader WidgetLoader;
|
||||
public ILoadScreen LoadScreen = null;
|
||||
|
||||
public SheetBuilder SheetBuilder;
|
||||
public CursorSheetBuilder CursorSheetBuilder;
|
||||
|
||||
public ModData( params string[] mods )
|
||||
{
|
||||
Manifest = new Manifest( mods );
|
||||
@@ -49,10 +49,13 @@ namespace OpenRA
|
||||
.Where(p => Directory.Exists(p))
|
||||
.SelectMany(p => Directory.GetDirectories(p)).ToList();
|
||||
|
||||
return paths.Select(p => new MapStub(new Folder(p, 0))).ToDictionary(m => m.Uid);
|
||||
return paths.Select(p => new MapStub(new Folder(p, int.MaxValue))).ToDictionary(m => m.Uid);
|
||||
}
|
||||
|
||||
string cachedTheatre = null;
|
||||
string cachedTileset = null;
|
||||
bool previousMapHadSequences = true;
|
||||
IFolder previousMapMount = null;
|
||||
|
||||
public Map PrepareMap(string uid)
|
||||
{
|
||||
LoadScreen.Display();
|
||||
@@ -60,16 +63,34 @@ 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]);
|
||||
|
||||
// unload the previous map mount if we have one
|
||||
if (previousMapMount != null) FileSystem.Unmount(previousMapMount);
|
||||
|
||||
// Adds the map its container to the FileSystem
|
||||
// allowing the map to use custom assets
|
||||
// Container should have the lowest priority of all (ie int max)
|
||||
FileSystem.Mount(map.Container);
|
||||
|
||||
// Store a reference so we can unload it next time
|
||||
previousMapMount = map.Container;
|
||||
|
||||
Rules.LoadRules(Manifest, map);
|
||||
if (map.Theater != cachedTheatre)
|
||||
|
||||
if (map.Tileset != cachedTileset
|
||||
|| previousMapHadSequences || map.Sequences.Count > 0)
|
||||
{
|
||||
SheetBuilder = new SheetBuilder( TextureChannel.Red );
|
||||
SpriteSheetBuilder.Initialize( Rules.TileSets[map.Tileset] );
|
||||
SequenceProvider.Initialize(Manifest.Sequences);
|
||||
CursorSheetBuilder = new CursorSheetBuilder( this );
|
||||
CursorProvider.Initialize(Manifest.Cursors);
|
||||
cachedTheatre = map.Theater;
|
||||
SequenceProvider.Initialize(Manifest.Sequences, map.Sequences);
|
||||
cachedTileset = map.Tileset;
|
||||
}
|
||||
|
||||
previousMapHadSequences = map.Sequences.Count > 0;
|
||||
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,23 +11,43 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using OpenRA.Network;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
[Flags]
|
||||
enum OrderFields : byte
|
||||
{
|
||||
TargetActor = 0x01,
|
||||
TargetLocation = 0x02,
|
||||
TargetString = 0x04,
|
||||
Queued = 0x08,
|
||||
ExtraLocation = 0x10,
|
||||
}
|
||||
|
||||
static class OrderFieldsExts
|
||||
{
|
||||
public static bool HasField(this OrderFields of, OrderFields f)
|
||||
{
|
||||
return (of & f) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class Order
|
||||
{
|
||||
public readonly string OrderString;
|
||||
public readonly Actor Subject;
|
||||
public readonly Actor TargetActor;
|
||||
public readonly int2 TargetLocation;
|
||||
public readonly string TargetString;
|
||||
public readonly bool Queued;
|
||||
public Actor TargetActor;
|
||||
public int2 TargetLocation;
|
||||
public string TargetString;
|
||||
public int2 ExtraLocation;
|
||||
public bool IsImmediate;
|
||||
|
||||
public Player Player { get { return Subject.Owner; } }
|
||||
|
||||
public Order(string orderString, Actor subject,
|
||||
Actor targetActor, int2 targetLocation, string targetString, bool queued)
|
||||
Order(string orderString, Actor subject,
|
||||
Actor targetActor, int2 targetLocation, string targetString, bool queued, int2 extraLocation)
|
||||
{
|
||||
this.OrderString = orderString;
|
||||
this.Subject = subject;
|
||||
@@ -35,24 +55,11 @@ namespace OpenRA
|
||||
this.TargetLocation = targetLocation;
|
||||
this.TargetString = targetString;
|
||||
this.Queued = queued;
|
||||
this.ExtraLocation = extraLocation;
|
||||
}
|
||||
|
||||
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, 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, bool queued)
|
||||
: this(orderString, subject, null, int2.Zero, null, queued, int2.Zero) { }
|
||||
|
||||
public byte[] Serialize()
|
||||
{
|
||||
@@ -80,13 +87,25 @@ namespace OpenRA
|
||||
w.Write( (byte)0xFF );
|
||||
w.Write(OrderString);
|
||||
w.Write(UIntFromActor(Subject));
|
||||
w.Write(UIntFromActor(TargetActor));
|
||||
w.Write(TargetLocation.X);
|
||||
w.Write(TargetLocation.Y);
|
||||
w.Write(TargetString != null);
|
||||
|
||||
OrderFields fields = 0;
|
||||
if (TargetActor != null) fields |= OrderFields.TargetActor;
|
||||
if (TargetLocation != int2.Zero) fields |= OrderFields.TargetLocation;
|
||||
if (TargetString != null) fields |= OrderFields.TargetString;
|
||||
if (Queued) fields |= OrderFields.Queued;
|
||||
if (ExtraLocation != int2.Zero) fields |= OrderFields.ExtraLocation;
|
||||
|
||||
w.Write((byte)fields);
|
||||
|
||||
if (TargetActor != null)
|
||||
w.Write(UIntFromActor(TargetActor));
|
||||
if (TargetLocation != int2.Zero)
|
||||
w.Write(TargetLocation);
|
||||
if (TargetString != null)
|
||||
w.Write(TargetString);
|
||||
w.Write(Queued);
|
||||
if (ExtraLocation != int2.Zero)
|
||||
w.Write(ExtraLocation);
|
||||
|
||||
return ret.ToArray();
|
||||
}
|
||||
}
|
||||
@@ -100,19 +119,19 @@ namespace OpenRA
|
||||
{
|
||||
var order = r.ReadString();
|
||||
var subjectId = r.ReadUInt32();
|
||||
var targetActorId = r.ReadUInt32();
|
||||
var targetLocation = new int2(r.ReadInt32(), 0);
|
||||
targetLocation.Y = r.ReadInt32();
|
||||
var targetString = null as string;
|
||||
if (r.ReadBoolean())
|
||||
targetString = r.ReadString();
|
||||
var queued = r.ReadBoolean();
|
||||
var flags = (OrderFields)r.ReadByte();
|
||||
|
||||
var targetActorId = flags.HasField(OrderFields.TargetActor) ? r.ReadUInt32() : 0xffffffff;
|
||||
var targetLocation = flags.HasField(OrderFields.TargetLocation) ? r.ReadInt2() : int2.Zero;
|
||||
var targetString = flags.HasField(OrderFields.TargetString) ? r.ReadString() : null;
|
||||
var queued = flags.HasField(OrderFields.Queued);
|
||||
var extraLocation = flags.HasField(OrderFields.ExtraLocation) ? r.ReadInt2() : int2.Zero;
|
||||
|
||||
Actor subject, targetActor;
|
||||
if( !TryGetActorFromUInt( world, subjectId, out subject ) || !TryGetActorFromUInt( world, targetActorId, out targetActor ) )
|
||||
return null;
|
||||
|
||||
return new Order( order, subject, targetActor, targetLocation, targetString, queued);
|
||||
return new Order( order, subject, targetActor, targetLocation, targetString, queued, extraLocation);
|
||||
}
|
||||
|
||||
case 0xfe:
|
||||
@@ -120,7 +139,7 @@ namespace OpenRA
|
||||
var name = r.ReadString();
|
||||
var data = r.ReadString();
|
||||
|
||||
return new Order( name, null, data ) { IsImmediate = true };
|
||||
return new Order( name, null, false ) { IsImmediate = true, TargetString = data };
|
||||
}
|
||||
|
||||
default:
|
||||
@@ -130,8 +149,8 @@ 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(
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -164,32 +183,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, false) { IsImmediate = true, TargetString = text};
|
||||
}
|
||||
|
||||
public static Order TeamChat(string text)
|
||||
{
|
||||
return new Order("TeamChat", null, text) { IsImmediate = true };
|
||||
return new Order("TeamChat", null, false) { IsImmediate = true, TargetString = text };
|
||||
}
|
||||
|
||||
public static Order Command(string text)
|
||||
{
|
||||
return new Order("Command", null, text) { IsImmediate = true };
|
||||
return new Order("Command", null, false) { IsImmediate = true, TargetString = text };
|
||||
}
|
||||
|
||||
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, false) { TargetLocation = new int2(count, 0), TargetString = item };
|
||||
}
|
||||
|
||||
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, false) { TargetLocation = new int2(pause ? 1 : 0, 0), TargetString = item };
|
||||
}
|
||||
|
||||
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, false) { TargetLocation = new int2(count, 0), TargetString = item };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,10 +8,8 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA.Network
|
||||
{
|
||||
@@ -47,5 +45,18 @@ namespace OpenRA.Network
|
||||
}
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
public static int2 ReadInt2(this BinaryReader r)
|
||||
{
|
||||
var x = r.ReadInt32();
|
||||
var y = r.ReadInt32();
|
||||
return new int2(x, y);
|
||||
}
|
||||
|
||||
public static void Write(this BinaryWriter w, int2 p)
|
||||
{
|
||||
w.Write(p.X);
|
||||
w.Write(p.Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,6 @@ namespace OpenRA.Network
|
||||
report.Traits.Clear();
|
||||
foreach (var a in orderManager.world.Queries.WithTraitMultiple<object>())
|
||||
{
|
||||
if (a.Trait is ITraitNotSynced ) continue;
|
||||
var sync = Sync.CalculateSyncHash(a.Trait);
|
||||
if (sync != 0)
|
||||
report.Traits.Add(new TraitReport()
|
||||
|
||||
@@ -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
|
||||
@@ -36,14 +36,9 @@ namespace OpenRA.Network
|
||||
|
||||
switch (order.OrderString)
|
||||
{
|
||||
case "Chat":
|
||||
case "Chat":
|
||||
{
|
||||
var client = orderManager.LobbyInfo.ClientWithIndex(clientId);
|
||||
|
||||
if (Game.IsHost && Game.Settings.Server.Extension != null && !Game.Settings.Server.Extension.OnIngameChat(client, order.TargetString, false))
|
||||
break;
|
||||
|
||||
|
||||
if (client != null)
|
||||
{
|
||||
var player = world != null ? world.FindPlayerByClient(client) : null;
|
||||
@@ -54,7 +49,6 @@ namespace OpenRA.Network
|
||||
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);
|
||||
@@ -68,9 +62,6 @@ namespace OpenRA.Network
|
||||
{
|
||||
var client = orderManager.LobbyInfo.ClientWithIndex(clientId);
|
||||
|
||||
if (Game.IsHost && Game.Settings.Server.Extension != null && !Game.Settings.Server.Extension.OnIngameChat(client, order.TargetString, true))
|
||||
break;
|
||||
|
||||
if (client != null)
|
||||
{
|
||||
if (world == null)
|
||||
@@ -125,18 +116,18 @@ namespace OpenRA.Network
|
||||
var targetPlayer = order.Player.World.players[order.TargetLocation.X];
|
||||
var newStance = (Stance)order.TargetLocation.Y;
|
||||
|
||||
if (Game.IsHost && Game.Settings.Server.Extension != null)
|
||||
Game.Settings.Server.Extension.OnIngameSetStance(order.Player, targetPlayer, newStance);
|
||||
|
||||
|
||||
SetPlayerStance(world, order.Player, targetPlayer, 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));
|
||||
|
||||
// automatically declare war reciprocally
|
||||
if (newStance == Stance.Enemy && targetPlayer.Stances[order.Player] == Stance.Ally)
|
||||
{
|
||||
SetPlayerStance(world, targetPlayer, order.Player, newStance);
|
||||
Game.Debug("{0} has reciprocated",targetPlayer.PlayerName);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -154,12 +145,12 @@ namespace OpenRA.Network
|
||||
}
|
||||
}
|
||||
|
||||
static void SetPlayerStance(World w, Player a, Player b, Stance s)
|
||||
static void SetPlayerStance(World w, Player p, Player target, Stance s)
|
||||
{
|
||||
var oldStance = a.Stances[b];
|
||||
a.Stances[b] = s;
|
||||
if (b == w.LocalPlayer)
|
||||
w.WorldActor.Trait<Shroud>().UpdatePlayerStance(w, b, oldStance, s);
|
||||
var oldStance = p.Stances[target];
|
||||
p.Stances[target] = s;
|
||||
if (target == w.LocalPlayer)
|
||||
w.WorldActor.Trait<Shroud>().UpdatePlayerStance(w, p, oldStance, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace OpenRA
|
||||
.ToList();
|
||||
|
||||
// Namespaces from each mod assembly
|
||||
foreach (var a in manifest.Assemblies.Concat(manifest.LocalAssemblies))
|
||||
foreach (var a in manifest.Assemblies)
|
||||
{
|
||||
var asm = Assembly.LoadFile(Path.GetFullPath(a));
|
||||
asms.AddRange(asm.GetNamespaces().Select(ns => Pair.New(asm, ns)));
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?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>
|
||||
@@ -83,17 +83,10 @@
|
||||
<Compile Include="Traits\Player\PlayerResources.cs" />
|
||||
<Compile Include="Traits\World\Shroud.cs" />
|
||||
<Compile Include="Widgets\ChatEntryWidget.cs" />
|
||||
<Compile Include="Widgets\Delegates\ConnectionDialogsDelegate.cs" />
|
||||
<Compile Include="Widgets\Delegates\CreateServerMenuDelegate.cs" />
|
||||
<Compile Include="Widgets\Delegates\DiplomacyDelegate.cs" />
|
||||
<Compile Include="Widgets\Delegates\MainMenuButtonsDelegate.cs" />
|
||||
<Compile Include="Widgets\Delegates\ServerBrowserDelegate.cs" />
|
||||
<Compile Include="Widgets\Delegates\SettingsMenuDelegate.cs" />
|
||||
<Compile Include="Widgets\MapPreviewWidget.cs" />
|
||||
<Compile Include="Widgets\WidgetUtils.cs" />
|
||||
<Compile Include="Effects\DelayedAction.cs" />
|
||||
<Compile Include="Effects\FlashTarget.cs" />
|
||||
<Compile Include="Effects\MoveFlash.cs" />
|
||||
<Compile Include="Exts.cs" />
|
||||
<Compile Include="GameRules\ActorInfo.cs" />
|
||||
<Compile Include="GameRules\VoiceInfo.cs" />
|
||||
@@ -111,7 +104,6 @@
|
||||
<Compile Include="Server\MasterServerQuery.cs" />
|
||||
<Compile Include="Server\Server.cs" />
|
||||
<Compile Include="Server\ServerOrder.cs" />
|
||||
<Compile Include="ShroudRenderer.cs" />
|
||||
<Compile Include="Sound.cs" />
|
||||
<Compile Include="Support\PerfHistory.cs" />
|
||||
<Compile Include="Sync.cs" />
|
||||
@@ -126,7 +118,6 @@
|
||||
<Compile Include="Graphics\CursorSheetBuilder.cs" />
|
||||
<Compile Include="Graphics\LineRenderer.cs" />
|
||||
<Compile Include="Graphics\WorldRenderer.cs" />
|
||||
<Compile Include="Traits\Activities\Idle.cs" />
|
||||
<Compile Include="Orders\IOrderGenerator.cs" />
|
||||
<Compile Include="Player.cs" />
|
||||
<Compile Include="Graphics\Sheet.cs" />
|
||||
@@ -165,17 +156,12 @@
|
||||
<Compile Include="Widgets\BackgroundWidget.cs" />
|
||||
<Compile Include="Widgets\LabelWidget.cs" />
|
||||
<Compile Include="Widgets\CheckboxWidget.cs" />
|
||||
<Compile Include="Widgets\Delegates\MusicPlayerDelegate.cs" />
|
||||
<Compile Include="Widgets\PerfGraphWidget.cs" />
|
||||
<Compile Include="Widgets\Delegates\PerfDebugDelegate.cs" />
|
||||
<Compile Include="Widgets\Delegates\LobbyDelegate.cs" />
|
||||
<Compile Include="Widgets\ColorBlockWidget.cs" />
|
||||
<Compile Include="GameRules\MusicInfo.cs" />
|
||||
<Compile Include="Widgets\ImageWidget.cs" />
|
||||
<Compile Include="Widgets\TextFieldWidget.cs" />
|
||||
<Compile Include="Widgets\ChatDisplayWidget.cs" />
|
||||
<Compile Include="Widgets\Delegates\MapChooserDelegate.cs" />
|
||||
<Compile Include="Widgets\ListBoxWidget.cs" />
|
||||
<Compile Include="Widgets\SliderWidget.cs" />
|
||||
<Compile Include="Widgets\TimerWidget.cs" />
|
||||
<Compile Include="Widgets\ShpImageWidget.cs" />
|
||||
@@ -186,12 +172,14 @@
|
||||
<Compile Include="Traits\RevealsShroud.cs" />
|
||||
<Compile Include="Traits\Health.cs" />
|
||||
<Compile Include="Widgets\VqaPlayerWidget.cs" />
|
||||
<Compile Include="Widgets\Delegates\VideoPlayerDelegate.cs" />
|
||||
<Compile Include="GameRules\Settings.cs" />
|
||||
<Compile Include="Support\Arguments.cs" />
|
||||
<Compile Include="Traits\ActorStance.cs" />
|
||||
<Compile Include="Traits\Armor.cs" />
|
||||
<Compile Include="Graphics\CursorProvider.cs" />
|
||||
<Compile Include="Server\TraitInterfaces.cs" />
|
||||
<Compile Include="Widgets\ScrollPanelWidget.cs" />
|
||||
<Compile Include="Graphics\ShroudRenderer.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">
|
||||
@@ -208,17 +196,12 @@
|
||||
<Compile Include="Network\Session.cs" />
|
||||
<Compile Include="ObjectCreator.cs" />
|
||||
<Compile Include="Network\SyncReport.cs" />
|
||||
<Compile Include="Server\IServerExtension.cs" />
|
||||
<Compile Include="Server\NullServerExtension.cs" />
|
||||
<Compile Include="Traits\BaseBuilding.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="Widgets\PasswordFieldWidget.cs" />
|
||||
<Compile Include="Widgets\Delegates\DeveloperModeDelegate.cs" />
|
||||
<Compile Include="Widgets\ScrollingTextWidget.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -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, false) { TargetLocation = xy };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,15 +77,7 @@ namespace OpenRA.Orders
|
||||
Game.Renderer.Flush();
|
||||
}
|
||||
|
||||
public void RenderAfterWorld(WorldRenderer wr, World world)
|
||||
{
|
||||
foreach (var a in world.Selection.Actors)
|
||||
if (!a.Destroyed)
|
||||
foreach (var t in a.TraitsImplementing<IPostRenderSelection>())
|
||||
t.RenderAfterWorld(wr, a);
|
||||
|
||||
Game.Renderer.Flush();
|
||||
}
|
||||
public void RenderAfterWorld(WorldRenderer wr, World world) {}
|
||||
|
||||
public string GetCursor(World world, int2 xy, MouseInput mi) { return world.Map.IsInMap(xy) ? cursor : "generic-blocked"; }
|
||||
}
|
||||
@@ -84,6 +89,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]
|
||||
|
||||
@@ -44,13 +44,15 @@ namespace OpenRA.Orders
|
||||
.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()))
|
||||
;
|
||||
if (actorsInvolved.Any())
|
||||
yield return new Order("CreateGroup", actorsInvolved.First().Owner.PlayerActor, false)
|
||||
{
|
||||
TargetString = string.Join(",", actorsInvolved.Select(a => a.ActorID.ToString()).ToArray())
|
||||
};
|
||||
|
||||
|
||||
foreach (var o in orders)
|
||||
yield return CheckSameOrder(o.iot, o.trait.IssueOrder(o.self, o.iot, o.target));
|
||||
yield return CheckSameOrder(o.iot, o.trait.IssueOrder(o.self, o.iot, o.target, mi.Modifiers.HasModifier(Modifiers.Shift)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,17 +90,14 @@ namespace OpenRA.Orders
|
||||
custom.RenderAfterWorld(wr, world);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var a in world.Selection.Actors)
|
||||
if (!a.Destroyed)
|
||||
foreach (var t in a.TraitsImplementing<IPostRenderSelection>())
|
||||
t.RenderAfterWorld( wr, a );
|
||||
|
||||
|
||||
Game.Renderer.Flush();
|
||||
}
|
||||
|
||||
public string GetCursor( World world, int2 xy, MouseInput mi )
|
||||
{
|
||||
{
|
||||
bool useSelect = false;
|
||||
|
||||
var custom = world.WorldActor.TraitOrDefault<ICustomUnitOrderGenerator>();
|
||||
if (custom != null)
|
||||
{
|
||||
@@ -108,20 +107,21 @@ namespace OpenRA.Orders
|
||||
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();
|
||||
|
||||
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 )
|
||||
@@ -129,19 +129,10 @@ namespace OpenRA.Orders
|
||||
if (self.Owner != self.World.LocalPlayer)
|
||||
return null;
|
||||
|
||||
if (!self.World.Map.IsInMap(xy.X, xy.Y))
|
||||
return null;
|
||||
|
||||
if (self.Destroyed)
|
||||
return null;
|
||||
|
||||
//var old = self.TraitsImplementing<IIssueOrder>()
|
||||
// .OrderByDescending( x => x.OrderPriority( self, xy, mi, underCursor ) )
|
||||
// .Select( x => x.IssueOrder( self, xy, mi, underCursor ) )
|
||||
// .FirstOrDefault( x => x != null );
|
||||
//if( old != null )
|
||||
// return old;
|
||||
|
||||
if( mi.Button == MouseButton.Right )
|
||||
{
|
||||
var uim = self.World.WorldActor.Trait<UnitInfluence>();
|
||||
@@ -154,9 +145,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 ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,13 +40,12 @@ namespace OpenRA
|
||||
public readonly PlayerReference PlayerRef;
|
||||
public bool IsBot;
|
||||
|
||||
public ShroudRenderer Shroud;
|
||||
public Shroud Shroud { get { return World.LocalShroud; }}
|
||||
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;
|
||||
@@ -69,8 +68,6 @@ namespace OpenRA
|
||||
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;
|
||||
|
||||
@@ -17,25 +17,25 @@ namespace OpenRA.Server
|
||||
{
|
||||
public class Connection
|
||||
{
|
||||
internal Socket socket;
|
||||
internal List<byte> data = new List<byte>();
|
||||
internal ReceiveState State = ReceiveState.Header;
|
||||
internal int ExpectLength = 8;
|
||||
internal int Frame = 0;
|
||||
public Socket socket;
|
||||
public List<byte> data = new List<byte>();
|
||||
public ReceiveState State = ReceiveState.Header;
|
||||
public int ExpectLength = 8;
|
||||
public int Frame = 0;
|
||||
|
||||
internal int MostRecentFrame = 0;
|
||||
public int MostRecentFrame = 0;
|
||||
|
||||
/* client data */
|
||||
public int PlayerIndex { get; internal set; }
|
||||
public int PlayerIndex;
|
||||
|
||||
internal byte[] PopBytes(int n)
|
||||
public byte[] PopBytes(int n)
|
||||
{
|
||||
var result = data.GetRange(0, n);
|
||||
data.RemoveRange(0, n);
|
||||
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;
|
||||
}
|
||||
|
||||
internal 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 };
|
||||
}
|
||||
|
||||
@@ -1,84 +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.Network;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Server
|
||||
{
|
||||
public interface IServerExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// Return true to use the built-in handling
|
||||
/// </summary>
|
||||
bool OnReadyUp(Connection conn, Session.Client client);
|
||||
void OnStartGame();
|
||||
/// <summary>
|
||||
/// Return true to use the built-in handling
|
||||
/// </summary>
|
||||
bool OnNickChange(Connection conn, Session.Client client, string newName);
|
||||
|
||||
/// <summary>
|
||||
/// Return true to use the built-in handling
|
||||
/// </summary>
|
||||
bool OnRaceChange(Connection conn, Session.Client client, string newRace);
|
||||
|
||||
/// <summary>
|
||||
/// Return true to use the built-in handling
|
||||
/// </summary>
|
||||
bool OnSlotChange(Connection conn, Session.Client client, Session.Slot slot, Map map);
|
||||
|
||||
/// <summary>
|
||||
/// Return true to use the built-in handling
|
||||
/// </summary>
|
||||
bool OnTeamChange(Connection conn, Session.Client getClient, int team);
|
||||
|
||||
/// <summary>
|
||||
/// Return true to use the built-in handling
|
||||
/// </summary>
|
||||
bool OnSpawnpointChange(Connection conn, Session.Client getClient, int spawnPoint);
|
||||
|
||||
/// <summary>
|
||||
/// Return true to use the built-in handling
|
||||
/// </summary>
|
||||
bool OnColorChange(Connection conn, Session.Client getClient, Color fromArgb, Color color);
|
||||
|
||||
/// <summary>
|
||||
/// Return true to use the built-in handling
|
||||
/// </summary>
|
||||
bool OnChat(Connection conn, string message, bool teamChat);
|
||||
|
||||
void OnServerStart();
|
||||
void OnServerStop(bool forced);
|
||||
void OnLoadMap(Map map);
|
||||
|
||||
/// <summary>
|
||||
/// Return false to drop the connection
|
||||
/// </summary>
|
||||
bool OnValidateConnection(bool gameStarted, Connection newConn);
|
||||
|
||||
void OnLobbySync(Session lobbyInfo, bool gameStarted);
|
||||
/// <summary>
|
||||
/// Return true to use the built-in handling
|
||||
/// </summary>
|
||||
bool OnPingMasterServer(Session lobbyInfo, bool gameStarted);
|
||||
|
||||
/// <summary>
|
||||
/// Return true to use the built-in handling
|
||||
/// </summary>
|
||||
bool OnIngameChat(Session.Client client, string message, bool teamChat);
|
||||
|
||||
void OnIngameSetStance(Player player, Player stanceForPlayer, Stance newStance);
|
||||
|
||||
void OnLobbyUp();
|
||||
void OnRejoinLobby(World world);
|
||||
}
|
||||
}
|
||||
@@ -1,40 +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.Network;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Server
|
||||
{
|
||||
public class NullServerExtension : IServerExtension
|
||||
{
|
||||
public virtual bool OnReadyUp(Connection conn, Session.Client client) { return true; }
|
||||
public virtual void OnStartGame() { }
|
||||
public virtual bool OnNickChange(Connection conn, Session.Client client, string newName) { return true; }
|
||||
public virtual bool OnRaceChange(Connection conn, Session.Client client, string newRace) { return true; }
|
||||
public virtual bool OnSlotChange(Connection conn, Session.Client client, Session.Slot slot, Map map) { return true; }
|
||||
public virtual bool OnTeamChange(Connection conn, Session.Client getClient, int team) { return true; }
|
||||
public virtual bool OnSpawnpointChange(Connection conn, Session.Client getClient, int spawnPoint) { return true; }
|
||||
public virtual bool OnColorChange(Connection conn, Session.Client getClient, Color fromArgb, Color color) { return true; }
|
||||
public virtual bool OnChat(Connection conn, string message, bool teamChat) { return true; }
|
||||
public virtual void OnServerStart() { }
|
||||
public virtual void OnServerStop(bool forced) { }
|
||||
// Good spot to manipulate number of spectators! ie set Server.MaxSpectators
|
||||
public virtual void OnLoadMap(Map map) { }
|
||||
public virtual bool OnValidateConnection(bool gameStarted, Connection newConn) { return true; }
|
||||
public virtual void OnLobbySync(Session lobbyInfo, bool gameStarted) { }
|
||||
public virtual bool OnPingMasterServer(Session lobbyInfo, bool gameStarted) { return true; }
|
||||
public virtual bool OnIngameChat(Session.Client client, string message, bool teamChat) { return true; }
|
||||
public virtual void OnIngameSetStance(Player player, Player stanceForPlayer, Stance newStance) { }
|
||||
public virtual void OnLobbyUp() { }
|
||||
public virtual void OnRejoinLobby(World world) { }
|
||||
}
|
||||
}
|
||||
@@ -23,81 +23,54 @@ using OpenRA.Network;
|
||||
|
||||
namespace OpenRA.Server
|
||||
{
|
||||
static class Server
|
||||
public class Server
|
||||
{
|
||||
public static Connection[] Connections
|
||||
{
|
||||
get { return conns.ToArray(); }
|
||||
}
|
||||
|
||||
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;
|
||||
internal 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.
|
||||
|
||||
public static int MaxSpectators = 4; // How many spectators to allow // @todo Expose this as an option
|
||||
|
||||
static int lastPing = 0;
|
||||
static bool isInternetServer;
|
||||
static string masterServerUrl;
|
||||
static bool isInitialPing;
|
||||
static ModData ModData;
|
||||
static Map Map;
|
||||
|
||||
public static void StopListening()
|
||||
public void Shutdown()
|
||||
{
|
||||
conns.Clear();
|
||||
GameStarted = false;
|
||||
foreach (var t in ServerTraits.WithInterface<INotifyServerShutdown>())
|
||||
t.ServerShutdown(this);
|
||||
|
||||
try { listener.Stop(); }
|
||||
catch { }
|
||||
|
||||
E(e => e.OnServerStop(true));
|
||||
}
|
||||
|
||||
public static void E(Action<IServerExtension> f)
|
||||
{
|
||||
E(g => { f(g); return true; });
|
||||
}
|
||||
|
||||
public static bool E(Func<IServerExtension, bool> f)
|
||||
{
|
||||
return Game.Settings.Server.Extension == null ||
|
||||
f(Game.Settings.Server.Extension);
|
||||
}
|
||||
|
||||
public static void ServerMain(ModData modData, Settings settings, string map)
|
||||
|
||||
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);
|
||||
@@ -113,73 +86,32 @@ namespace OpenRA.Server
|
||||
throw new InvalidOperationException( "Unable to start server: port is already in use" );
|
||||
}
|
||||
|
||||
E(e => e.OnServerStart());
|
||||
|
||||
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 if (conns.Count > 0) 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)
|
||||
{
|
||||
listener.Stop();
|
||||
GameStarted = false;
|
||||
E(e => e.OnServerStop(false));
|
||||
break;
|
||||
}
|
||||
}
|
||||
} ) { 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();
|
||||
|
||||
E(e => e.OnLoadMap(Map));
|
||||
|
||||
// Generate slots for spectators
|
||||
for (int i = 0; i < MaxSpectators; i++)
|
||||
lobbyInfo.Slots.Add(new Session.Slot
|
||||
{
|
||||
Spectator = true,
|
||||
Index = lobbyInfo.Slots.Count(),
|
||||
MapPlayer = null,
|
||||
Bot = null
|
||||
});
|
||||
}
|
||||
|
||||
/* lobby rework todo:
|
||||
@@ -187,7 +119,7 @@ namespace OpenRA.Server
|
||||
* for manual spawnpoint choosing.
|
||||
* - 256 max players is a dirty hack
|
||||
*/
|
||||
static int ChooseFreePlayerIndex()
|
||||
int ChooseFreePlayerIndex()
|
||||
{
|
||||
for (var i = 0; i < 256; i++)
|
||||
if (conns.All(c => c.PlayerIndex != i))
|
||||
@@ -196,13 +128,7 @@ namespace OpenRA.Server
|
||||
throw new InvalidOperationException("Already got 256 players");
|
||||
}
|
||||
|
||||
static int ChooseFreeSlot()
|
||||
{
|
||||
return lobbyInfo.Slots.First(s => !s.Closed && s.Bot == null
|
||||
&& !lobbyInfo.Clients.Any( c => c.Slot == s.Index )).Index;
|
||||
}
|
||||
|
||||
static void AcceptConnection()
|
||||
void AcceptConnection()
|
||||
{
|
||||
Socket newSocket = null;
|
||||
|
||||
@@ -217,17 +143,7 @@ namespace OpenRA.Server
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var newConn = new Connection { socket = newSocket };
|
||||
|
||||
|
||||
if (!E(e => e.OnValidateConnection(GameStarted, newConn)))
|
||||
{
|
||||
DropClient(newConn, new Exception() );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (GameStarted)
|
||||
@@ -247,38 +163,13 @@ namespace OpenRA.Server
|
||||
newConn.socket.Send(BitConverter.GetBytes(newConn.PlayerIndex));
|
||||
conns.Add(newConn);
|
||||
|
||||
var defaults = new GameRules.PlayerSettings();
|
||||
|
||||
var client = 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(),
|
||||
};
|
||||
|
||||
var slotData = lobbyInfo.Slots.FirstOrDefault( x => x.Index == client.Slot );
|
||||
if (slotData != null)
|
||||
SyncClientToPlayerReference(client, Map.Players[slotData.MapPlayer]);
|
||||
|
||||
lobbyInfo.Clients.Add(client);
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -294,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
|
||||
{
|
||||
@@ -308,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);
|
||||
@@ -320,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);
|
||||
@@ -337,369 +228,56 @@ namespace OpenRA.Server
|
||||
catch (EndOfStreamException) { }
|
||||
catch (NotImplementedException) { }
|
||||
}
|
||||
|
||||
public static void SyncClientToPlayerReference(Session.Client c, PlayerReference pr)
|
||||
{
|
||||
if (pr == null)
|
||||
return;
|
||||
if (pr.LockColor)
|
||||
{
|
||||
c.Color1 = pr.Color;
|
||||
c.Color2 = pr.Color2;
|
||||
}
|
||||
if (pr.LockRace)
|
||||
c.Country = pr.Race;
|
||||
}
|
||||
|
||||
public 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 (Game.Settings.Server.Extension== null || Game.Settings.Server.Extension.OnReadyUp(conn, client))
|
||||
{
|
||||
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());
|
||||
|
||||
E(e => e.OnStartGame());
|
||||
|
||||
PingMasterServer();
|
||||
return true;
|
||||
}},
|
||||
{ "name",
|
||||
s =>
|
||||
{
|
||||
Log.Write("server", "Player@{0} is now known as {1}", conn.socket.RemoteEndPoint, s);
|
||||
|
||||
if (E(e => e.OnNickChange(conn, GetClient(conn), 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 =>
|
||||
{
|
||||
if (E(e => e.OnRaceChange(conn, GetClient(conn), s)))
|
||||
GetClient(conn).Country = s;
|
||||
|
||||
SyncLobbyInfo();
|
||||
return true;
|
||||
}},
|
||||
{ "spectator",
|
||||
s =>
|
||||
{
|
||||
var slotData = lobbyInfo.Slots.Where(ax => ax.Spectator && !lobbyInfo.Clients.Any(l => l.Slot == ax.Index)).FirstOrDefault();
|
||||
if (slotData == null)
|
||||
return true;
|
||||
|
||||
var cl = GetClient(conn);
|
||||
|
||||
if (E(e => e.OnSlotChange(conn, cl, slotData, Map)))
|
||||
{
|
||||
cl.Slot = slotData.Index;
|
||||
SyncClientToPlayerReference(cl, slotData.MapPlayer != null
|
||||
? Map.Players[slotData.MapPlayer] : null);
|
||||
}
|
||||
|
||||
SyncLobbyInfo();
|
||||
return true;
|
||||
}},
|
||||
{ "team",
|
||||
s =>
|
||||
{
|
||||
int team;
|
||||
if (!int.TryParse(s, out team)) { Log.Write("server", "Invalid team: {0}", s ); return false; }
|
||||
if (E(e => e.OnTeamChange(conn, GetClient(conn), team)))
|
||||
{
|
||||
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;
|
||||
}
|
||||
if (E(e => e.OnSpawnpointChange(conn, GetClient(conn), spawnPoint)))
|
||||
{
|
||||
GetClient(conn).SpawnPoint = spawnPoint;
|
||||
}
|
||||
SyncLobbyInfo();
|
||||
return true;
|
||||
}},
|
||||
{ "color",
|
||||
s =>
|
||||
{
|
||||
var c = s.Split(',').Select(cc => int.Parse(cc)).ToArray();
|
||||
var c1 = Color.FromArgb(c[0], c[1], c[2]);
|
||||
var c2 = Color.FromArgb(c[3], c[4], c[5]);
|
||||
|
||||
if (E(e => e.OnColorChange(conn, GetClient(conn), c1, c2)))
|
||||
{
|
||||
GetClient(conn).Color1 = c1;
|
||||
GetClient(conn).Color2 = c2;
|
||||
}
|
||||
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;
|
||||
|
||||
var cl = GetClient(conn);
|
||||
|
||||
if (E(e => e.OnSlotChange(conn, cl, slotData, Map)))
|
||||
{
|
||||
cl.Slot = slot;
|
||||
SyncClientToPlayerReference(cl, slotData.MapPlayer != null
|
||||
? Map.Players[slotData.MapPlayer] : null);
|
||||
}
|
||||
|
||||
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;
|
||||
var slotData = lobbyInfo.Slots.FirstOrDefault( x => x.Index == client.Slot );
|
||||
if (slotData != null)
|
||||
SyncClientToPlayerReference(client, Map.Players[slotData.MapPlayer]);
|
||||
|
||||
client.State = Session.ClientState.NotReady;
|
||||
}
|
||||
|
||||
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)
|
||||
public void SendChat(Connection asConn, string text)
|
||||
{
|
||||
DispatchOrders(asConn, 0, new ServerOrder("Chat", text).Serialize());
|
||||
}
|
||||
|
||||
static void SendDisconnected(Connection asConn)
|
||||
public void SendDisconnected(Connection asConn)
|
||||
{
|
||||
DispatchOrders(asConn, 0, new ServerOrder("Disconnected", "").Serialize());
|
||||
}
|
||||
|
||||
static void InterpretServerOrder(Connection conn, ServerOrder so)
|
||||
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))
|
||||
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", "Bad server command: {0}", so.Data);
|
||||
SendChatTo(conn, "Bad server command.");
|
||||
};
|
||||
Log.Write("server", "Unknown server command: {0}", so.Data);
|
||||
SendChatTo(conn, "Unknown server command: {0}".F(so.Data));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case "Chat":
|
||||
case "TeamChat":
|
||||
case "Disconnected":
|
||||
if (E(e => e.OnChat(conn, so.Data, so.Name == "TeamChat")))
|
||||
foreach (var c in conns.Except(conn).ToArray())
|
||||
DispatchOrdersToClient(c, GetClient(conn).Index, 0, so.Serialize());
|
||||
break;
|
||||
foreach (var c in conns.Except(conn).ToArray())
|
||||
DispatchOrdersToClient(c, GetClient(conn).Index, 0, so.Serialize());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
@@ -715,65 +293,28 @@ namespace OpenRA.Server
|
||||
SyncLobbyInfo();
|
||||
}
|
||||
|
||||
static void SyncLobbyInfo()
|
||||
public void SyncLobbyInfo()
|
||||
{
|
||||
E(e => e.OnLobbySync(lobbyInfo, GameStarted));
|
||||
|
||||
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 } );
|
||||
|
||||
if (!E(e => e.OnPingMasterServer(lobbyInfo, GameStarted)))
|
||||
return;
|
||||
DispatchOrders(null, 0,
|
||||
new ServerOrder("StartGame", "").Serialize());
|
||||
|
||||
lastPing = Environment.TickCount;
|
||||
isBusy = true;
|
||||
|
||||
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()");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,192 +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;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
public class ShroudRenderer
|
||||
{
|
||||
Traits.Shroud shroud;
|
||||
Sprite[] shadowBits = SpriteSheetBuilder.LoadAllSprites("shadow");
|
||||
Sprite[,] sprites, fogSprites;
|
||||
|
||||
bool dirty = true;
|
||||
bool disabled = false;
|
||||
Map map;
|
||||
|
||||
public Rectangle? Bounds { get { return shroud.exploredBounds; } }
|
||||
|
||||
public ShroudRenderer(Player owner, Map map)
|
||||
{
|
||||
this.shroud = owner.World.WorldActor.Trait<Traits.Shroud>();
|
||||
this.map = map;
|
||||
|
||||
sprites = new Sprite[map.MapSize.X, map.MapSize.Y];
|
||||
fogSprites = new Sprite[map.MapSize.X, map.MapSize.Y];
|
||||
|
||||
shroud.Dirty += () => dirty = true;
|
||||
}
|
||||
|
||||
public bool Disabled
|
||||
{
|
||||
get { return disabled; }
|
||||
set { disabled = value; dirty = true;}
|
||||
}
|
||||
|
||||
public bool IsExplored(int2 xy) { return IsExplored(xy.X, xy.Y); }
|
||||
public bool IsExplored(int x, int y)
|
||||
{
|
||||
if (disabled)
|
||||
return true;
|
||||
return shroud.exploredCells[x,y];
|
||||
}
|
||||
|
||||
public bool IsVisible(int2 xy) { return IsVisible(xy.X, xy.Y); }
|
||||
public bool IsVisible(int x, int y)
|
||||
{
|
||||
if (disabled)
|
||||
return true;
|
||||
return shroud.visibleCells[x,y] != 0;
|
||||
}
|
||||
|
||||
static readonly byte[][] SpecialShroudTiles =
|
||||
{
|
||||
new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
|
||||
new byte[] { 32, 32, 25, 25, 19, 19, 20, 20 },
|
||||
new byte[] { 33, 33, 33, 33, 26, 26, 26, 26, 21, 21, 21, 21, 23, 23, 23, 23 },
|
||||
new byte[] { 36, 36, 36, 36, 30, 30, 30, 30 },
|
||||
new byte[] { 34, 16, 34, 16, 34, 16, 34, 16, 27, 22, 27, 22, 27, 22, 27, 22 },
|
||||
new byte[] { 44 },
|
||||
new byte[] { 37, 37, 37, 37, 37, 37, 37, 37, 31, 31, 31, 31, 31, 31, 31, 31 },
|
||||
new byte[] { 40 },
|
||||
new byte[] { 35, 24, 17, 18 },
|
||||
new byte[] { 39, 39, 29, 29 },
|
||||
new byte[] { 45 },
|
||||
new byte[] { 43 },
|
||||
new byte[] { 38, 28 },
|
||||
new byte[] { 42 },
|
||||
new byte[] { 41 },
|
||||
new byte[] { 46 },
|
||||
};
|
||||
|
||||
Sprite ChooseShroud(int i, int j)
|
||||
{
|
||||
if( !shroud.exploredCells[ i, j ] ) return shadowBits[ 0xf ];
|
||||
|
||||
// bits are for unexploredness: up, right, down, left
|
||||
var v = 0;
|
||||
// bits are for unexploredness: TL, TR, BR, BL
|
||||
var u = 0;
|
||||
|
||||
if( !shroud.exploredCells[ i, j - 1 ] ) { v |= 1; u |= 3; }
|
||||
if( !shroud.exploredCells[ i + 1, j ] ) { v |= 2; u |= 6; }
|
||||
if( !shroud.exploredCells[ i, j + 1 ] ) { v |= 4; u |= 12; }
|
||||
if( !shroud.exploredCells[ i - 1, j ] ) { v |= 8; u |= 9; }
|
||||
|
||||
var uSides = u;
|
||||
|
||||
if( !shroud.exploredCells[ i - 1, j - 1 ] ) u |= 1;
|
||||
if( !shroud.exploredCells[ i + 1, j - 1 ] ) u |= 2;
|
||||
if( !shroud.exploredCells[ i + 1, j + 1 ] ) u |= 4;
|
||||
if( !shroud.exploredCells[ i - 1, j + 1 ] ) u |= 8;
|
||||
|
||||
return shadowBits[ SpecialShroudTiles[ u ^ uSides ][ v ] ];
|
||||
}
|
||||
|
||||
Sprite ChooseFog(int i, int j)
|
||||
{
|
||||
if (shroud.visibleCells[i, j] == 0) return shadowBits[0xf];
|
||||
if (!shroud.exploredCells[i, j]) return shadowBits[0xf];
|
||||
|
||||
// bits are for unexploredness: up, right, down, left
|
||||
var v = 0;
|
||||
// bits are for unexploredness: TL, TR, BR, BL
|
||||
var u = 0;
|
||||
|
||||
if (shroud.visibleCells[i, j - 1] == 0) { v |= 1; u |= 3; }
|
||||
if (shroud.visibleCells[i + 1, j] == 0) { v |= 2; u |= 6; }
|
||||
if (shroud.visibleCells[i, j + 1] == 0) { v |= 4; u |= 12; }
|
||||
if (shroud.visibleCells[i - 1, j] == 0) { v |= 8; u |= 9; }
|
||||
|
||||
var uSides = u;
|
||||
|
||||
if (shroud.visibleCells[i - 1, j - 1] == 0) u |= 1;
|
||||
if (shroud.visibleCells[i + 1, j - 1] == 0) u |= 2;
|
||||
if (shroud.visibleCells[i + 1, j + 1] == 0) u |= 4;
|
||||
if (shroud.visibleCells[i - 1, j + 1] == 0) u |= 8;
|
||||
|
||||
return shadowBits[SpecialShroudTiles[u ^ uSides][v]];
|
||||
}
|
||||
|
||||
internal void Draw( WorldRenderer wr )
|
||||
{
|
||||
if (disabled)
|
||||
return;
|
||||
|
||||
if (dirty)
|
||||
{
|
||||
dirty = false;
|
||||
for (int i = map.TopLeft.X; i < map.BottomRight.X; i++)
|
||||
for (int j = map.TopLeft.Y; j < map.BottomRight.Y; j++)
|
||||
sprites[i, j] = ChooseShroud(i, j);
|
||||
for (int i = map.TopLeft.X; i < map.BottomRight.X; i++)
|
||||
for (int j = map.TopLeft.Y; j < map.BottomRight.Y; j++)
|
||||
fogSprites[i, j] = ChooseFog(i, j);
|
||||
}
|
||||
|
||||
var clipRect = Bounds.HasValue ? Rectangle.Intersect(Bounds.Value, map.Bounds) : map.Bounds;
|
||||
clipRect = Rectangle.Intersect(Game.viewport.ViewBounds(), clipRect);
|
||||
var miny = clipRect.Top;
|
||||
var maxy = clipRect.Bottom;
|
||||
var minx = clipRect.Left;
|
||||
var maxx = clipRect.Right;
|
||||
|
||||
DrawShroud( wr, minx, miny, maxx, maxy, fogSprites, "fog" );
|
||||
DrawShroud( wr, minx, miny, maxx, maxy, sprites, "shroud" );
|
||||
}
|
||||
|
||||
void DrawShroud( WorldRenderer wr, int minx, int miny, int maxx, int maxy, Sprite[,] s, string pal )
|
||||
{
|
||||
var shroudPalette = wr.GetPaletteIndex(pal);
|
||||
|
||||
for (var j = miny; j < maxy; j++)
|
||||
{
|
||||
var starti = minx;
|
||||
for (var i = minx; i < maxx; i++)
|
||||
{
|
||||
if (s[i, j] == shadowBits[0x0f])
|
||||
continue;
|
||||
|
||||
if (starti != i)
|
||||
{
|
||||
s[starti, j].DrawAt(
|
||||
Game.CellSize * new float2(starti, j),
|
||||
shroudPalette,
|
||||
new float2(Game.CellSize * (i - starti), Game.CellSize));
|
||||
starti = i + 1;
|
||||
}
|
||||
|
||||
s[i, j].DrawAt(
|
||||
Game.CellSize * new float2(i, j),
|
||||
shroudPalette);
|
||||
starti = i + 1;
|
||||
}
|
||||
|
||||
if (starti < maxx)
|
||||
s[starti, j].DrawAt(
|
||||
Game.CellSize * new float2(starti, j),
|
||||
shroudPalette,
|
||||
new float2(Game.CellSize * (maxx - starti), Game.CellSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ using OpenRA.FileFormats;
|
||||
|
||||
namespace OpenRA.Support
|
||||
{
|
||||
static class PerfHistory
|
||||
public static class PerfHistory
|
||||
{
|
||||
static readonly Color[] colors = { Color.Red, Color.Green,
|
||||
Color.Blue, Color.Yellow,
|
||||
@@ -45,7 +45,7 @@ namespace OpenRA.Support
|
||||
}
|
||||
}
|
||||
|
||||
class PerfItem
|
||||
public class PerfItem
|
||||
{
|
||||
public readonly Color c;
|
||||
public readonly string Name;
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
namespace OpenRA.Traits.Activities
|
||||
{
|
||||
public abstract class CancelableActivity : IActivity
|
||||
{
|
||||
|
||||
@@ -1,17 +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
|
||||
|
||||
namespace OpenRA.Traits.Activities
|
||||
{
|
||||
public class Idle : CancelableActivity
|
||||
{
|
||||
public override IActivity Tick(Actor self) { return NextActivity; }
|
||||
}
|
||||
}
|
||||
@@ -1,18 +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 OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
/* tag trait for "bases": mcv/fact */
|
||||
public class BaseBuildingInfo : TraitInfo<BaseBuilding> { }
|
||||
public class BaseBuilding { }
|
||||
}
|
||||
@@ -9,7 +9,8 @@
|
||||
#endregion
|
||||
|
||||
using System.Drawing;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Effects;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
@@ -57,9 +58,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);
|
||||
@@ -67,6 +70,34 @@ namespace OpenRA.Traits
|
||||
Game.Renderer.LineRenderer.DrawLine(p + new float2(1, -1), p + new float2(-1, -1), c, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class LineTargetExts
|
||||
{
|
||||
public static void SetTargetLine(this Actor self, Target target, Color color)
|
||||
{
|
||||
self.SetTargetLine(target, color, true);
|
||||
}
|
||||
|
||||
public static void SetTargetLine(this Actor self, Target target, Color color, bool display)
|
||||
{
|
||||
if (self.Owner != self.World.LocalPlayer)
|
||||
return;
|
||||
|
||||
self.World.AddFrameEndTask(w =>
|
||||
{
|
||||
if (self.Destroyed) return;
|
||||
if (target.IsActor && display)
|
||||
w.Add(new FlashTarget(target.Actor));
|
||||
|
||||
var line = self.TraitOrDefault<DrawLineToTarget>();
|
||||
if (line != null)
|
||||
if (display)
|
||||
line.SetTarget(self, target, color);
|
||||
else
|
||||
line.SetTargetSilently(self, target, color);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,16 +6,11 @@
|
||||
* 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.Traits.Activities;
|
||||
#endregion
|
||||
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.GameRules;
|
||||
using OpenRA.FileFormats;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
public class DeveloperModeInfo : ITraitInfo
|
||||
@@ -19,6 +20,7 @@ namespace OpenRA.Traits
|
||||
public bool DisableShroud = false;
|
||||
public bool PathDebug = false;
|
||||
public bool UnitInfluenceDebug = false;
|
||||
public bool UnlimitedPower;
|
||||
|
||||
public object Create (ActorInitializer init) { return new DeveloperMode(this); }
|
||||
}
|
||||
@@ -31,7 +33,8 @@ namespace OpenRA.Traits
|
||||
[Sync] public bool FastBuild;
|
||||
[Sync] public bool DisableShroud;
|
||||
[Sync] public bool PathDebug;
|
||||
[Sync] public bool UnitInfluenceDebug;
|
||||
[Sync] public bool UnitInfluenceDebug;
|
||||
[Sync] public bool UnlimitedPower;
|
||||
|
||||
public DeveloperMode(DeveloperModeInfo info)
|
||||
{
|
||||
@@ -40,7 +43,8 @@ namespace OpenRA.Traits
|
||||
FastCharge = Info.FastCharge;
|
||||
DisableShroud = Info.DisableShroud;
|
||||
PathDebug = Info.PathDebug;
|
||||
UnitInfluenceDebug = info.UnitInfluenceDebug;
|
||||
UnitInfluenceDebug = info.UnitInfluenceDebug;
|
||||
UnlimitedPower = info.UnlimitedPower;
|
||||
}
|
||||
|
||||
public void ResolveOrder (Actor self, Order order)
|
||||
@@ -73,7 +77,7 @@ namespace OpenRA.Traits
|
||||
{
|
||||
DisableShroud ^= true;
|
||||
if (self.World.LocalPlayer == self.Owner)
|
||||
self.World.LocalPlayer.Shroud.Disabled = DisableShroud;
|
||||
self.World.LocalShroud.Disabled = DisableShroud;
|
||||
break;
|
||||
}
|
||||
case "DevPathDebug":
|
||||
@@ -91,6 +95,11 @@ namespace OpenRA.Traits
|
||||
if (self.World.LocalPlayer == self.Owner)
|
||||
self.World.WorldActor.Trait<Shroud>().ExploreAll(self.World);
|
||||
break;
|
||||
}
|
||||
case "DevUnlimitedPower":
|
||||
{
|
||||
UnlimitedPower ^= true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
|
||||
@@ -17,9 +17,10 @@ namespace OpenRA.Traits
|
||||
public abstract class RenderSimpleInfo : ITraitInfo
|
||||
{
|
||||
public readonly string Image = null;
|
||||
public readonly string[] OverrideTheater = null;
|
||||
public readonly string[] OverrideTileset = null;
|
||||
public readonly string[] OverrideImage = null;
|
||||
public readonly string Palette = null;
|
||||
public readonly float Scale = 1f;
|
||||
public abstract object Create(ActorInitializer init);
|
||||
}
|
||||
|
||||
@@ -28,32 +29,44 @@ namespace OpenRA.Traits
|
||||
public Dictionary<string, AnimationWithOffset> anims = new Dictionary<string, AnimationWithOffset>();
|
||||
public Animation anim { get { return anims[""].Animation; } protected set { anims[""].Animation = value; } }
|
||||
|
||||
public static string GetImage(ActorInfo actor, string Tileset)
|
||||
{
|
||||
var Info = actor.Traits.Get<RenderSimpleInfo>();
|
||||
if (Info.OverrideTileset != null && Tileset != null)
|
||||
for (int i = 0; i < Info.OverrideTileset.Length; i++)
|
||||
if (Info.OverrideTileset[i] == Tileset)
|
||||
return Info.OverrideImage[i];
|
||||
|
||||
return Info.Image ?? actor.Name;
|
||||
}
|
||||
|
||||
string cachedImage = null;
|
||||
public string GetImage(Actor self)
|
||||
{
|
||||
if (cachedImage != null)
|
||||
return cachedImage;
|
||||
|
||||
var Info = self.Info.Traits.Get<RenderSimpleInfo>();
|
||||
if (Info.OverrideTheater != null)
|
||||
for (int i = 0; i < Info.OverrideTheater.Length; i++)
|
||||
if (Info.OverrideTheater[i] == self.World.Map.Theater)
|
||||
return cachedImage = Info.OverrideImage[i];
|
||||
|
||||
return cachedImage = Info.Image ?? self.Info.Name;
|
||||
return cachedImage = GetImage(self.Info, self.World.Map.Tileset);
|
||||
}
|
||||
|
||||
RenderSimpleInfo Info;
|
||||
public RenderSimple(Actor self, Func<int> baseFacing)
|
||||
{
|
||||
anims.Add( "", new Animation( GetImage(self), baseFacing ) );
|
||||
Info = self.Info.Traits.Get<RenderSimpleInfo>();
|
||||
}
|
||||
|
||||
public virtual IEnumerable<Renderable> Render( Actor self )
|
||||
{
|
||||
var palette = self.Info.Traits.Get<RenderSimpleInfo>().Palette;
|
||||
|
||||
foreach( var a in anims.Values )
|
||||
if( a.DisableFunc == null || !a.DisableFunc() )
|
||||
yield return ( palette == null ) ? a.Image( self ) : a.Image( self ).WithPalette(palette);
|
||||
{
|
||||
Renderable ret = a.Image( self );
|
||||
if (Info.Scale != 1f)
|
||||
ret = ret.WithScale(Info.Scale).WithPos(ret.Pos + 0.5f*ret.Sprite.size*(1 - Info.Scale));
|
||||
yield return ( Info.Palette == null ) ? ret : ret.WithPalette(Info.Palette);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Tick(Actor self)
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
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
|
||||
@@ -30,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);
|
||||
|
||||
@@ -39,15 +39,16 @@ 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 IValidateOrder { bool OrderValidation(OrderManager orderManager, World world, int clientId, Order order);
|
||||
}
|
||||
@@ -72,7 +73,7 @@ namespace OpenRA.Traits
|
||||
Color RadarSignatureColor(Actor self);
|
||||
}
|
||||
|
||||
public interface IVisibilityModifier { bool IsVisible(Actor self, Player byPlayer); }
|
||||
public interface IVisibilityModifier { bool IsVisible(Actor self); }
|
||||
public interface IRadarColorModifier { Color RadarColorOverride(Actor self); }
|
||||
public interface IHasLocation
|
||||
{
|
||||
@@ -104,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(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); }
|
||||
@@ -149,15 +151,6 @@ namespace OpenRA.Traits
|
||||
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;
|
||||
Scale = 1f; /* default */
|
||||
}
|
||||
public Renderable(Sprite sprite, float2 pos, string palette, int z, int zOffset, float scale)
|
||||
{
|
||||
Sprite = sprite;
|
||||
@@ -169,12 +162,12 @@ namespace OpenRA.Traits
|
||||
}
|
||||
|
||||
public Renderable(Sprite sprite, float2 pos, string palette, int z)
|
||||
: this(sprite, pos, palette, z, 0) { }
|
||||
|
||||
: this(sprite, pos, palette, z, 0, 1f) { }
|
||||
|
||||
public Renderable(Sprite sprite, float2 pos, string palette, int z, float scale)
|
||||
: this(sprite, pos, palette, z, 0, scale) { }
|
||||
|
||||
|
||||
public Renderable WithScale(float newScale) { return new Renderable(Sprite, Pos, Palette, Z, ZOffset, newScale); }
|
||||
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); }
|
||||
@@ -201,7 +194,7 @@ namespace OpenRA.Traits
|
||||
}
|
||||
|
||||
public interface IRenderOverlay { void Render( WorldRenderer wr ); }
|
||||
public interface INotifyIdle { void Idle(Actor self); }
|
||||
public interface INotifyIdle { void TickIdle(Actor self); }
|
||||
|
||||
public interface IBlocksBullets { }
|
||||
|
||||
@@ -210,15 +203,13 @@ namespace OpenRA.Traits
|
||||
public interface IPostRenderSelection { void RenderAfterWorld(WorldRenderer wr, Actor self); }
|
||||
public interface IPreRenderSelection { void RenderBeforeWorld(WorldRenderer wr, Actor self); }
|
||||
|
||||
public interface ITraitNotSynced{} // Traits marked with NotSynced arent sync-checked
|
||||
|
||||
public struct Target // a target: either an actor, or a fixed location.
|
||||
{
|
||||
Actor actor;
|
||||
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)
|
||||
@@ -242,5 +233,8 @@ namespace OpenRA.Traits
|
||||
{
|
||||
string[] TargetTypes { get; }
|
||||
IEnumerable<int2> TargetableCells( Actor self );
|
||||
bool TargetableBy(Actor self, Actor byActor);
|
||||
}
|
||||
|
||||
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,12 +100,7 @@ namespace OpenRA.Traits
|
||||
public static Renderable Centered(Actor self, Sprite s, float2 location)
|
||||
{
|
||||
var pal = self.Owner == null ? "player0" : self.Owner.Palette;
|
||||
var scale = self.TraitOrDefault<Scale>();
|
||||
var scaleModifier = 1f;
|
||||
if (scale != null)
|
||||
scaleModifier = scale.Info.Value;
|
||||
|
||||
var loc = location - 0.5f * s.size * scaleModifier;
|
||||
var loc = location - 0.5f * s.size;
|
||||
|
||||
return new Renderable(s, loc.Round(), pal, (int)self.CenterLocation.Y);
|
||||
}
|
||||
@@ -115,6 +111,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(); }
|
||||
|
||||
@@ -26,27 +26,15 @@ namespace OpenRA.Traits
|
||||
|
||||
public void Render( WorldRenderer wr )
|
||||
{
|
||||
var cliprect = Game.viewport.ShroudBounds( world );
|
||||
cliprect = Rectangle.Intersect(Game.viewport.ViewBounds(), cliprect);
|
||||
|
||||
var minx = cliprect.Left;
|
||||
var maxx = cliprect.Right;
|
||||
|
||||
var miny = cliprect.Top;
|
||||
var maxy = cliprect.Bottom;
|
||||
|
||||
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++)
|
||||
var clip = Game.viewport.WorldBounds(world);
|
||||
for (int x = clip.Left; x < clip.Right; x++)
|
||||
for (int y = clip.Top; y < clip.Bottom; y++)
|
||||
{
|
||||
if (shroud != null && !shroud.IsExplored(new int2(x, y)))
|
||||
continue;
|
||||
if (!world.LocalShroud.IsExplored(new int2(x, y)))
|
||||
continue;
|
||||
|
||||
var c = content[x, y];
|
||||
if (c.image != null)
|
||||
@@ -67,8 +55,8 @@ namespace OpenRA.Traits
|
||||
|
||||
var map = w.Map;
|
||||
|
||||
for (int x = map.XOffset; x < map.XOffset + map.Width; x++)
|
||||
for (int y = map.YOffset; y < map.YOffset + map.Height; y++)
|
||||
for (int x = map.Bounds.Left; x < map.Bounds.Right; x++)
|
||||
for (int y = map.Bounds.Top; y < map.Bounds.Bottom; y++)
|
||||
{
|
||||
// Todo: Valid terrain should be specified in the resource
|
||||
if (!AllowResourceAt(new int2(x,y)))
|
||||
@@ -80,8 +68,8 @@ namespace OpenRA.Traits
|
||||
content[x, y].image = ChooseContent(content[x, y].type);
|
||||
}
|
||||
|
||||
for (int x = map.XOffset; x < map.XOffset + map.Width; x++)
|
||||
for (int y = map.YOffset; y < map.YOffset + map.Height; y++)
|
||||
for (int x = map.Bounds.Left; x < map.Bounds.Right; x++)
|
||||
for (int y = map.Bounds.Top; y < map.Bounds.Bottom; y++)
|
||||
if (content[x, y].type != null)
|
||||
{
|
||||
content[x, y].density = GetIdealDensity(x, y);
|
||||
|
||||
@@ -23,18 +23,31 @@ namespace OpenRA.Traits
|
||||
public class Shroud
|
||||
{
|
||||
Map map;
|
||||
|
||||
World world;
|
||||
|
||||
public int[,] visibleCells;
|
||||
public bool[,] exploredCells;
|
||||
public Rectangle? exploredBounds;
|
||||
Rectangle? exploredBounds;
|
||||
bool disabled = false;
|
||||
public bool Disabled
|
||||
{
|
||||
get { return disabled || world.LocalPlayer == null; }
|
||||
set { disabled = value; Dirty(); }
|
||||
}
|
||||
|
||||
public Rectangle? Bounds
|
||||
{
|
||||
get { return Disabled ? null : exploredBounds; }
|
||||
}
|
||||
|
||||
public event Action Dirty = () => { };
|
||||
|
||||
public Shroud(World world)
|
||||
{
|
||||
this.world = world;
|
||||
map = world.Map;
|
||||
visibleCells = new int[map.MapSize.X, map.MapSize.Y];
|
||||
exploredCells = new bool[map.MapSize.X, map.MapSize.Y];
|
||||
|
||||
world.ActorAdded += AddActor;
|
||||
world.ActorRemoved += RemoveActor;
|
||||
}
|
||||
@@ -48,10 +61,10 @@ namespace OpenRA.Traits
|
||||
{
|
||||
var min = a - new int2(r, r);
|
||||
var max = a + new int2(r, r);
|
||||
if (min.X < world.Map.XOffset - 1) min.X = world.Map.XOffset - 1;
|
||||
if (min.Y < world.Map.YOffset - 1) min.Y = world.Map.YOffset - 1;
|
||||
if (max.X > world.Map.XOffset + world.Map.Width) max.X = world.Map.XOffset + world.Map.Width;
|
||||
if (max.Y > world.Map.YOffset + world.Map.Height) max.Y = world.Map.YOffset + world.Map.Height;
|
||||
if (min.X < world.Map.Bounds.Left - 1) min.X = world.Map.Bounds.Left - 1;
|
||||
if (min.Y < world.Map.Bounds.Top - 1) min.Y = world.Map.Bounds.Top - 1;
|
||||
if (max.X > world.Map.Bounds.Right) max.X = world.Map.Bounds.Right;
|
||||
if (max.Y > world.Map.Bounds.Bottom) max.Y = world.Map.Bounds.Bottom;
|
||||
|
||||
for (var j = min.Y; j <= max.Y; j++)
|
||||
for (var i = min.X; i <= max.X; i++)
|
||||
@@ -90,13 +103,13 @@ namespace OpenRA.Traits
|
||||
}
|
||||
|
||||
var box = new Rectangle(p.X - v.range, p.Y - v.range, 2 * v.range + 1, 2 * v.range + 1);
|
||||
exploredBounds = exploredBounds.HasValue ?
|
||||
Rectangle.Union(exploredBounds.Value, box) : box;
|
||||
exploredBounds = (exploredBounds.HasValue) ? Rectangle.Union(exploredBounds.Value, box) : box;
|
||||
}
|
||||
|
||||
vis[a] = v;
|
||||
|
||||
Dirty();
|
||||
if (!Disabled)
|
||||
Dirty();
|
||||
}
|
||||
|
||||
public void UpdatePlayerStance(World w, Player player, Stance oldStance, Stance newStance)
|
||||
@@ -139,8 +152,9 @@ namespace OpenRA.Traits
|
||||
--visibleCells[q.X, q.Y];
|
||||
|
||||
vis.Remove(a);
|
||||
|
||||
Dirty();
|
||||
|
||||
if (!Disabled)
|
||||
Dirty();
|
||||
}
|
||||
|
||||
public void UpdateActor(Actor a)
|
||||
@@ -157,20 +171,21 @@ namespace OpenRA.Traits
|
||||
exploredCells[q.X, q.Y] = true;
|
||||
|
||||
var box = new Rectangle(center.X - range, center.Y - range, 2 * range + 1, 2 * range + 1);
|
||||
exploredBounds = exploredBounds.HasValue ?
|
||||
Rectangle.Union(exploredBounds.Value, box) : box;
|
||||
exploredBounds = (exploredBounds.HasValue) ? Rectangle.Union(exploredBounds.Value, box) : box;
|
||||
|
||||
Dirty();
|
||||
if (!Disabled)
|
||||
Dirty();
|
||||
}
|
||||
|
||||
public void ExploreAll(World world)
|
||||
{
|
||||
for (int i = map.TopLeft.X; i < map.BottomRight.X; i++)
|
||||
for (int j = map.TopLeft.Y; j < map.BottomRight.Y; j++)
|
||||
for (int i = map.Bounds.Left; i < map.Bounds.Right; i++)
|
||||
for (int j = map.Bounds.Top; j < map.Bounds.Bottom; j++)
|
||||
exploredCells[i, j] = true;
|
||||
exploredBounds = new Rectangle(world.Map.TopLeft.X,world.Map.TopLeft.Y,world.Map.Width,world.Map.Height);
|
||||
exploredBounds = world.Map.Bounds;
|
||||
|
||||
Dirty();
|
||||
if (!Disabled)
|
||||
Dirty();
|
||||
}
|
||||
|
||||
public void ResetExploration() // for `hide map` crate
|
||||
@@ -179,7 +194,43 @@ namespace OpenRA.Traits
|
||||
for (var i = 0; i <= exploredCells.GetUpperBound(0); i++)
|
||||
exploredCells[i, j] = visibleCells[i, j] > 0;
|
||||
|
||||
Dirty();
|
||||
if (!Disabled)
|
||||
Dirty();
|
||||
}
|
||||
|
||||
public bool IsExplored(int2 xy) { return IsExplored(xy.X, xy.Y); }
|
||||
public bool IsExplored(int x, int y)
|
||||
{
|
||||
if (!map.IsInMap(x, y))
|
||||
return false;
|
||||
|
||||
if (Disabled)
|
||||
return true;
|
||||
|
||||
return exploredCells[x,y];
|
||||
}
|
||||
|
||||
public bool IsVisible(int2 xy) { return IsVisible(xy.X, xy.Y); }
|
||||
public bool IsVisible(int x, int y)
|
||||
{
|
||||
if (Disabled)
|
||||
return true;
|
||||
|
||||
// Visibility is allowed to extend beyond the map cordon so that
|
||||
// the fog tiles are not visible at the edge of the world
|
||||
if (x < 0 || x >= map.MapSize.X || y < 0 || y >= map.MapSize.Y)
|
||||
return false;
|
||||
|
||||
return visibleCells[x,y] != 0;
|
||||
}
|
||||
|
||||
// Actors are hidden under shroud, but not under fog by default
|
||||
public bool IsVisible(Actor a)
|
||||
{
|
||||
if (a.TraitsImplementing<IVisibilityModifier>().Any(t => !t.IsVisible(a)))
|
||||
return false;
|
||||
|
||||
return Disabled || a.Owner == a.World.LocalPlayer || GetVisOrigins(a).Any(o => IsExplored(o));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,10 +49,10 @@ namespace OpenRA.Traits
|
||||
{
|
||||
var bounds = a.Actor.GetBounds(true);
|
||||
|
||||
if (bounds.Right <= Game.CellSize * self.World.Map.XOffset) continue;
|
||||
if (bounds.Bottom <= Game.CellSize * self.World.Map.YOffset) continue;
|
||||
if (bounds.Left >= Game.CellSize * (self.World.Map.XOffset + self.World.Map.Width)) continue;
|
||||
if (bounds.Top >= Game.CellSize * (self.World.Map.YOffset + self.World.Map.Height)) continue;
|
||||
if (bounds.Right <= Game.CellSize * self.World.Map.Bounds.Left) continue;
|
||||
if (bounds.Bottom <= Game.CellSize * self.World.Map.Bounds.Top) continue;
|
||||
if (bounds.Left >= Game.CellSize * self.World.Map.Bounds.Right) continue;
|
||||
if (bounds.Top >= Game.CellSize * self.World.Map.Bounds.Bottom) continue;
|
||||
|
||||
var i1 = Math.Max(0, (int)bounds.Left / scale);
|
||||
var i2 = Math.Min(bins.GetUpperBound(0), (int)bounds.Right / scale);
|
||||
|
||||
@@ -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 )
|
||||
|
||||
@@ -27,13 +27,13 @@ namespace OpenRA
|
||||
unitDebug = SynthesizeTile(0x04);
|
||||
}
|
||||
|
||||
static Sprite SynthesizeTile(byte paletteIndex)
|
||||
public static Sprite SynthesizeTile(byte paletteIndex)
|
||||
{
|
||||
byte[] data = new byte[Game.CellSize * Game.CellSize];
|
||||
|
||||
for (int i = 0; i < Game.CellSize; i++)
|
||||
for (int j = 0; j < Game.CellSize; j++)
|
||||
data[i * Game.CellSize + j] = ((i + j) % 4 < 2) ? (byte)0 : paletteIndex;
|
||||
data[i * Game.CellSize + j] = ((i+j) % 4 != 0) ? (byte)0 : paletteIndex;
|
||||
|
||||
return Game.modData.SheetBuilder.Add(data, new Size(Game.CellSize, Game.CellSize));
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ using OpenRA.Graphics;
|
||||
|
||||
namespace OpenRA.Widgets
|
||||
{
|
||||
class BackgroundWidget : Widget
|
||||
public class BackgroundWidget : Widget
|
||||
{
|
||||
public readonly string Background = "dialog";
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using OpenRA.Graphics;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OpenRA.Widgets
|
||||
{
|
||||
@@ -63,6 +64,9 @@ namespace OpenRA.Widgets
|
||||
return Depressed;
|
||||
}
|
||||
|
||||
public override int2 ChildOrigin { get { return RenderOrigin +
|
||||
((Depressed) ? new int2(VisualHeight, VisualHeight) : new int2(0, 0)); } }
|
||||
|
||||
public override void DrawInner( WorldRenderer wr )
|
||||
{
|
||||
var font = (Bold) ? Game.Renderer.BoldFont : Game.Renderer.RegularFont;
|
||||
@@ -70,13 +74,120 @@ namespace OpenRA.Widgets
|
||||
WidgetUtils.DrawPanel(Depressed ? "dialog3" : "dialog2", RenderBounds);
|
||||
|
||||
var text = GetText();
|
||||
|
||||
font.DrawText(text,
|
||||
new int2(RenderOrigin.X + Bounds.Width / 2, RenderOrigin.Y + Bounds.Height / 2)
|
||||
new int2(RenderOrigin.X + UsableWidth / 2, RenderOrigin.Y + Bounds.Height / 2)
|
||||
- new int2(font.Measure(text).X / 2,
|
||||
font.Measure(text).Y / 2) + stateOffset, Color.White);
|
||||
}
|
||||
|
||||
public override Widget Clone() { return new ButtonWidget(this); }
|
||||
public virtual int UsableWidth { get { return Bounds.Width; } }
|
||||
}
|
||||
|
||||
public class DropDownButtonWidget : ButtonWidget
|
||||
{
|
||||
public DropDownButtonWidget()
|
||||
: base()
|
||||
{
|
||||
}
|
||||
|
||||
protected DropDownButtonWidget(DropDownButtonWidget widget)
|
||||
: base(widget)
|
||||
{
|
||||
}
|
||||
|
||||
public override void DrawInner(WorldRenderer wr)
|
||||
{
|
||||
base.DrawInner(wr);
|
||||
var stateOffset = (Depressed) ? new int2(VisualHeight, VisualHeight) : new int2(0, 0);
|
||||
|
||||
var image = ChromeProvider.GetImage("scrollbar", "down_arrow");
|
||||
WidgetUtils.DrawRGBA( image,
|
||||
stateOffset + new float2( RenderBounds.Right - RenderBounds.Height + 4,
|
||||
RenderBounds.Top + (RenderBounds.Height - image.bounds.Height) / 2 ));
|
||||
|
||||
WidgetUtils.FillRectWithColor(new Rectangle(stateOffset.X + RenderBounds.Right - RenderBounds.Height,
|
||||
stateOffset.Y + RenderBounds.Top + 3, 1, RenderBounds.Height - 6),
|
||||
Color.White);
|
||||
}
|
||||
|
||||
public override Widget Clone() { return new DropDownButtonWidget(this); }
|
||||
public override int UsableWidth { get { return Bounds.Width - Bounds.Height; } } /* space for button */
|
||||
|
||||
public static void ShowDropPanel(Widget w, Widget panel, IEnumerable<Widget> dismissAfter, Func<bool> onDismiss)
|
||||
{
|
||||
var fullscreenMask = new ContainerWidget();
|
||||
// Don't use initializers - breaks on mono 2.6.7
|
||||
fullscreenMask.Bounds = new Rectangle(0, 0, Game.viewport.Width, Game.viewport.Height);
|
||||
fullscreenMask.ClickThrough = false;
|
||||
fullscreenMask.Visible = true;
|
||||
Widget.RootWidget.AddChild(fullscreenMask);
|
||||
|
||||
Action HideDropDown = () =>
|
||||
{
|
||||
Widget.RootWidget.Children.Remove(fullscreenMask);
|
||||
Widget.RootWidget.Children.Remove(panel);
|
||||
};
|
||||
|
||||
fullscreenMask.OnMouseDown = mi =>
|
||||
{
|
||||
if (onDismiss()) HideDropDown();
|
||||
return false;
|
||||
};
|
||||
|
||||
var oldBounds = panel.Bounds;
|
||||
panel.Bounds = new Rectangle(w.RenderOrigin.X, w.RenderOrigin.Y + w.Bounds.Height, oldBounds.Width, oldBounds.Height);
|
||||
panel.ClickThrough = false;
|
||||
panel.Visible = true;
|
||||
panel.OnMouseUp = mi => true;
|
||||
|
||||
foreach (var ww in dismissAfter)
|
||||
{
|
||||
var origMouseUp = ww.OnMouseUp;
|
||||
ww.OnMouseUp = mi => { var result = origMouseUp(mi); if (onDismiss()) HideDropDown(); return result; };
|
||||
}
|
||||
Widget.RootWidget.AddChild(panel);
|
||||
}
|
||||
|
||||
public static void ShowDropDown<T>(Widget w, IEnumerable<T> ts, Func<T, int, LabelWidget> ft)
|
||||
{
|
||||
var dropDown = new ScrollPanelWidget
|
||||
{
|
||||
Bounds = new Rectangle(w.RenderOrigin.X, w.RenderOrigin.Y + w.Bounds.Height, w.Bounds.Width, 100),
|
||||
Visible = true,
|
||||
ClickThrough = false,
|
||||
OnMouseUp = mi => true,
|
||||
};
|
||||
|
||||
var y = 0;
|
||||
List<LabelWidget> items = new List<LabelWidget>();
|
||||
List<Widget> dismissAfter = new List<Widget>();
|
||||
foreach (var t in ts)
|
||||
{
|
||||
var ww = ft(t, dropDown.Bounds.Width);
|
||||
dismissAfter.Add(ww);
|
||||
ww.ClickThrough = false;
|
||||
ww.IsVisible = () => true;
|
||||
ww.Bounds = new Rectangle(1, y, ww.Bounds.Width, ww.Bounds.Height);
|
||||
|
||||
ww.OnMouseMove = mi =>
|
||||
{
|
||||
items.Do(lw =>
|
||||
{
|
||||
lw.Background = null; ww.Background = "dialog2";
|
||||
}); return true;
|
||||
};
|
||||
|
||||
dropDown.AddChild(ww);
|
||||
items.Add(ww);
|
||||
|
||||
y += ww.Bounds.Height;
|
||||
}
|
||||
|
||||
dropDown.ContentHeight = y;
|
||||
dropDown.Bounds.Height = y + 2;
|
||||
ShowDropPanel(w,dropDown, dismissAfter, () => true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using OpenRA.Graphics;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OpenRA.Widgets
|
||||
{
|
||||
@@ -24,6 +25,7 @@ namespace OpenRA.Widgets
|
||||
public TextAlign Align = TextAlign.Left;
|
||||
public TextVAlign VAlign = TextVAlign.Middle;
|
||||
public bool Bold = false;
|
||||
public bool WordWrap = false;
|
||||
public Func<string> GetText;
|
||||
public Func<string> GetBackground;
|
||||
|
||||
@@ -58,7 +60,7 @@ namespace OpenRA.Widgets
|
||||
|
||||
int2 textSize = font.Measure(text);
|
||||
int2 position = RenderOrigin;
|
||||
|
||||
|
||||
if (VAlign == TextVAlign.Middle)
|
||||
position += new int2(0, (Bounds.Height - textSize.Y)/2);
|
||||
|
||||
@@ -69,7 +71,58 @@ namespace OpenRA.Widgets
|
||||
position += new int2((Bounds.Width - textSize.X)/2, 0);
|
||||
|
||||
if (Align == TextAlign.Right)
|
||||
position += new int2(Bounds.Width - textSize.X,0);
|
||||
position += new int2(Bounds.Width - textSize.X,0);
|
||||
|
||||
if (WordWrap)
|
||||
{
|
||||
if (textSize.X > Bounds.Width)
|
||||
{
|
||||
string[] lines = text.Split('\n');
|
||||
List<string> newLines = new List<string>();
|
||||
int i = 0;
|
||||
string line = lines[i++];
|
||||
while (true)
|
||||
{
|
||||
newLines.Add(line);
|
||||
int2 m = font.Measure(line);
|
||||
int spaceIndex = 0, start = line.Length - 1;
|
||||
|
||||
if (m.X <= Bounds.Width)
|
||||
{
|
||||
if (i < lines.Length - 1)
|
||||
{
|
||||
line = lines[i++];
|
||||
continue;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
while (m.X > Bounds.Width)
|
||||
{
|
||||
if (-1 == (spaceIndex = line.LastIndexOf(' ', start)))
|
||||
break;
|
||||
start = spaceIndex - 1;
|
||||
m = font.Measure(line.Substring(0, spaceIndex));
|
||||
}
|
||||
|
||||
if (spaceIndex != -1)
|
||||
{
|
||||
newLines.RemoveAt(newLines.Count - 1);
|
||||
newLines.Add(line.Substring(0, spaceIndex));
|
||||
line = line.Substring(spaceIndex + 1);
|
||||
}
|
||||
else if (i < lines.Length - 1)
|
||||
{
|
||||
line = lines[i++];
|
||||
continue;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
text = string.Join("\n", newLines.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
font.DrawText(text, position, Color.White);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace OpenRA.Widgets
|
||||
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)
|
||||
@@ -40,7 +40,7 @@ namespace OpenRA.Widgets
|
||||
|
||||
public int2 ConvertToPreview(MapStub map, int2 point)
|
||||
{
|
||||
return new int2(MapRect.X + (int)(PreviewScale*(point.X - map.TopLeft.X)) , MapRect.Y + (int)(PreviewScale*(point.Y - map.TopLeft.Y)));
|
||||
return new int2(MapRect.X + (int)(PreviewScale*(point.X - map.Bounds.Left)) , MapRect.Y + (int)(PreviewScale*(point.Y - map.Bounds.Top)));
|
||||
}
|
||||
|
||||
public override bool HandleInputInner(MouseInput mi)
|
||||
@@ -91,14 +91,14 @@ namespace OpenRA.Widgets
|
||||
mapChooserSheet = new Sheet(new Size( preview.Width, preview.Height ) );
|
||||
|
||||
mapChooserSheet.Texture.SetData( preview );
|
||||
mapChooserSprite = new Sprite( mapChooserSheet, new Rectangle( 0, 0, map.Width, map.Height ), TextureChannel.Alpha );
|
||||
mapChooserSprite = new Sprite( mapChooserSheet, new Rectangle( 0, 0, map.Bounds.Width, map.Bounds.Height ), TextureChannel.Alpha );
|
||||
|
||||
// Update map rect
|
||||
PreviewScale = Math.Min(RenderBounds.Width * 1.0f / map.Width, RenderBounds.Height * 1.0f / map.Height);
|
||||
var size = Math.Max(map.Width, map.Height);
|
||||
var dw = (int)(PreviewScale * (size - map.Width)) / 2;
|
||||
var dh = (int)(PreviewScale * (size - map.Height)) / 2;
|
||||
MapRect = new Rectangle(RenderBounds.X + dw, RenderBounds.Y + dh, (int)(map.Width * PreviewScale), (int)(map.Height * PreviewScale));
|
||||
PreviewScale = Math.Min(RenderBounds.Width * 1.0f / map.Bounds.Width, RenderBounds.Height * 1.0f / map.Bounds.Height);
|
||||
var size = Math.Max(map.Bounds.Width, map.Bounds.Height);
|
||||
var dw = (int)(PreviewScale * (size - map.Bounds.Width)) / 2;
|
||||
var dh = (int)(PreviewScale * (size - map.Bounds.Height)) / 2;
|
||||
MapRect = new Rectangle(RenderBounds.X + dw, RenderBounds.Y + dh, (int)(map.Bounds.Width * PreviewScale), (int)(map.Bounds.Height * PreviewScale));
|
||||
}
|
||||
|
||||
Game.Renderer.RgbaSpriteRenderer.DrawSprite( mapChooserSprite,
|
||||
|
||||
@@ -16,46 +16,13 @@ namespace OpenRA.Widgets
|
||||
{
|
||||
public class PasswordFieldWidget : TextFieldWidget
|
||||
{
|
||||
public PasswordFieldWidget()
|
||||
: base()
|
||||
{
|
||||
}
|
||||
|
||||
protected PasswordFieldWidget(PasswordFieldWidget widget)
|
||||
: base(widget)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
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();
|
||||
DrawWithString(new string('*', Text.Length));
|
||||
}
|
||||
|
||||
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() { }
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ using OpenRA.Graphics;
|
||||
|
||||
namespace OpenRA.Widgets
|
||||
{
|
||||
class ListBoxWidget : Widget
|
||||
public class ScrollPanelWidget : Widget
|
||||
{
|
||||
public readonly string Background = "dialog3";
|
||||
public readonly int ScrollbarWidth = 24;
|
||||
@@ -30,8 +30,8 @@ namespace OpenRA.Widgets
|
||||
Rectangle backgroundRect;
|
||||
Rectangle scrollbarRect;
|
||||
|
||||
public ListBoxWidget() : base() {}
|
||||
protected ListBoxWidget(ListBoxWidget other)
|
||||
public ScrollPanelWidget() : base() {}
|
||||
protected ScrollPanelWidget(ScrollPanelWidget other)
|
||||
: base(other)
|
||||
{
|
||||
Background = other.Background;
|
||||
@@ -71,7 +71,7 @@ namespace OpenRA.Widgets
|
||||
WidgetUtils.DrawRGBA(ChromeProvider.GetImage("scrollbar", "down_arrow"),
|
||||
new float2(downButtonRect.Left + downOffset, downButtonRect.Top + downOffset));
|
||||
|
||||
Game.Renderer.EnableScissor(backgroundRect.X, backgroundRect.Y + HeaderHeight, backgroundRect.Width, backgroundRect.Height - HeaderHeight);
|
||||
Game.Renderer.EnableScissor(backgroundRect.X+1, backgroundRect.Y + HeaderHeight+1, backgroundRect.Width-2, backgroundRect.Height - HeaderHeight-2);
|
||||
|
||||
foreach (var child in Children)
|
||||
child.Draw( wr );
|
||||
@@ -90,6 +90,8 @@ namespace OpenRA.Widgets
|
||||
{
|
||||
if (UpPressed && ListOffset <= 0) ListOffset += ScrollVelocity;
|
||||
if (DownPressed) ListOffset -= ScrollVelocity;
|
||||
|
||||
if (ListOffset > 0) ListOffset = 0;
|
||||
}
|
||||
|
||||
public override bool LoseFocus (MouseInput mi)
|
||||
@@ -115,6 +117,6 @@ namespace OpenRA.Widgets
|
||||
return (UpPressed || DownPressed);
|
||||
}
|
||||
|
||||
public override Widget Clone() { return new ListBoxWidget(this); }
|
||||
public override Widget Clone() { return new ScrollPanelWidget(this); }
|
||||
}
|
||||
}
|
||||
@@ -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 = "";
|
||||
|
||||
@@ -23,12 +23,9 @@ namespace OpenRA.Widgets
|
||||
public Func<bool> OnEnterKey = () => false;
|
||||
public Func<bool> OnTabKey = () => false;
|
||||
public Action OnLoseFocus = () => { };
|
||||
public int CursorPosition { get; protected set; }
|
||||
|
||||
public TextFieldWidget()
|
||||
: base()
|
||||
{
|
||||
}
|
||||
|
||||
public TextFieldWidget() : base() {}
|
||||
protected TextFieldWidget(TextFieldWidget widget)
|
||||
: base(widget)
|
||||
{
|
||||
@@ -59,8 +56,32 @@ namespace OpenRA.Widgets
|
||||
|
||||
blinkCycle = 10;
|
||||
showCursor = true;
|
||||
CursorPosition = ClosestCursorPosition(mi.Location.X);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public int ClosestCursorPosition(int x)
|
||||
{
|
||||
var font = (Bold) ? Game.Renderer.BoldFont : Game.Renderer.RegularFont;
|
||||
var textSize = font.Measure(Text);
|
||||
|
||||
var start = RenderOrigin.X + margin;
|
||||
if (textSize.X > Bounds.Width - 2 * margin && Focused)
|
||||
start += Bounds.Width - 2 * margin - textSize.X;
|
||||
|
||||
int minIndex = -1;
|
||||
int minValue = int.MaxValue;
|
||||
for (int i = 0; i <= Text.Length; i++)
|
||||
{
|
||||
var dist = Math.Abs(start + font.Measure(Text.Substring(0,i)).X - x);
|
||||
if (dist > minValue)
|
||||
break;
|
||||
minValue = dist;
|
||||
minIndex = i;
|
||||
}
|
||||
return minIndex;
|
||||
}
|
||||
|
||||
public override bool HandleKeyPressInner(KeyInput e)
|
||||
{
|
||||
@@ -76,23 +97,55 @@ namespace OpenRA.Widgets
|
||||
if (e.KeyChar == '\t' && OnTabKey())
|
||||
return true;
|
||||
|
||||
if (e.KeyName == "left")
|
||||
{
|
||||
if (CursorPosition > 0)
|
||||
CursorPosition--;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (e.KeyName == "right")
|
||||
{
|
||||
if (CursorPosition <= Text.Length-1)
|
||||
CursorPosition++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (e.KeyName == "delete")
|
||||
{
|
||||
if (Text.Length > 0 && CursorPosition < Text.Length)
|
||||
{
|
||||
Text = Text.Remove(CursorPosition, 1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
TypeChar(e.KeyChar);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void TypeChar(char c)
|
||||
{
|
||||
// backspace
|
||||
if (c == '\b' || c == 0x7f)
|
||||
{
|
||||
if (Text.Length > 0)
|
||||
Text = Text.Remove(Text.Length - 1);
|
||||
if (Text.Length > 0 && CursorPosition > 0)
|
||||
{
|
||||
Text = Text.Remove(CursorPosition - 1, 1);
|
||||
|
||||
CursorPosition--;
|
||||
}
|
||||
}
|
||||
else if (!char.IsControl(c))
|
||||
{
|
||||
if (MaxLength > 0 && Text.Length >= MaxLength)
|
||||
return;
|
||||
|
||||
Text += c;
|
||||
Text = Text.Insert(CursorPosition, c.ToString());
|
||||
|
||||
CursorPosition++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,17 +158,24 @@ namespace OpenRA.Widgets
|
||||
blinkCycle = 20;
|
||||
showCursor ^= true;
|
||||
}
|
||||
|
||||
base.Tick();
|
||||
}
|
||||
|
||||
public override void DrawInner( WorldRenderer wr )
|
||||
|
||||
int margin = 5;
|
||||
public virtual void DrawWithString(string text)
|
||||
{
|
||||
int margin = 5;
|
||||
if (text == null) text = "";
|
||||
|
||||
var font = (Bold) ? Game.Renderer.BoldFont : Game.Renderer.RegularFont;
|
||||
var cursor = (showCursor && Focused) ? "|" : "";
|
||||
var textSize = font.Measure(Text + "|");
|
||||
var pos = RenderOrigin;
|
||||
|
||||
if (CursorPosition > text.Length)
|
||||
CursorPosition = text.Length;
|
||||
|
||||
var textSize = font.Measure(text);
|
||||
var cursorPosition = font.Measure(text.Substring(0,CursorPosition));
|
||||
|
||||
WidgetUtils.DrawPanel("dialog3",
|
||||
new Rectangle(pos.X, pos.Y, Bounds.Width, Bounds.Height));
|
||||
|
||||
@@ -131,11 +191,19 @@ namespace OpenRA.Widgets
|
||||
Game.Renderer.EnableScissor(pos.X + margin, pos.Y, Bounds.Width - 2 * margin, Bounds.Bottom);
|
||||
}
|
||||
|
||||
font.DrawText(Text + cursor, textPos, Color.White);
|
||||
font.DrawText(text, textPos, Color.White);
|
||||
|
||||
if (showCursor && Focused)
|
||||
font.DrawText("|", new float2(textPos.X + cursorPosition.X - 2, textPos.Y), Color.White);
|
||||
|
||||
if (textSize.X > Bounds.Width - 2 * margin)
|
||||
Game.Renderer.DisableScissor();
|
||||
}
|
||||
|
||||
public override void DrawInner( WorldRenderer wr )
|
||||
{
|
||||
DrawWithString(Text);
|
||||
}
|
||||
|
||||
public override Widget Clone() { return new TextFieldWidget(this); }
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace OpenRA.Widgets
|
||||
|
||||
public override void DrawInner( WorldRenderer wr )
|
||||
{
|
||||
var s = WorldUtils.FormatTime(Game.LocalTick);
|
||||
var s = WidgetUtils.FormatTime(Game.LocalTick);
|
||||
var size = Game.Renderer.TitleFont.Measure(s);
|
||||
Game.Renderer.TitleFont.DrawText(s, new float2(RenderBounds.Left - size.X / 2, RenderBounds.Top - 20), Color.White);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -345,12 +345,27 @@ namespace OpenRA.Widgets
|
||||
}
|
||||
}
|
||||
|
||||
class ContainerWidget : Widget {
|
||||
public ContainerWidget() : base() { }
|
||||
public class ContainerWidget : Widget {
|
||||
public Func<string> GetBackground;
|
||||
public string Background = null;
|
||||
|
||||
public ContainerWidget() : base()
|
||||
{
|
||||
GetBackground = () => Background;
|
||||
}
|
||||
|
||||
public ContainerWidget(ContainerWidget other) : base(other)
|
||||
{
|
||||
Background = other.Background;
|
||||
GetBackground = other.GetBackground;
|
||||
}
|
||||
|
||||
public ContainerWidget(Widget other) : base(other) { }
|
||||
|
||||
public override void DrawInner( WorldRenderer wr ) { }
|
||||
public override void DrawInner( WorldRenderer wr )
|
||||
{
|
||||
var bg = GetBackground();
|
||||
if (bg != null)
|
||||
WidgetUtils.DrawPanel(bg, RenderBounds );
|
||||
}
|
||||
|
||||
public override string GetCursor(int2 pos) { return null; }
|
||||
public override Widget Clone() { return new ContainerWidget(this); }
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
@@ -41,7 +41,9 @@ namespace OpenRA
|
||||
public Widget LoadWidget( Dictionary<string, object> args, Widget parent, MiniYamlNode node)
|
||||
{
|
||||
var widget = NewWidget(node.Key, args);
|
||||
parent.AddChild( widget );
|
||||
|
||||
if (parent != null)
|
||||
parent.AddChild( widget );
|
||||
|
||||
foreach (var child in node.Value.Nodes)
|
||||
if (child.Key != "Children")
|
||||
|
||||
@@ -128,6 +128,18 @@ namespace OpenRA.Widgets
|
||||
if (ps.HasFlags(PanelSides.Right | PanelSides.Bottom))
|
||||
DrawRGBA(ss[7], new float2(Bounds.Right - ss[7].size.X, Bounds.Bottom - ss[7].size.Y));
|
||||
}
|
||||
|
||||
|
||||
public static string FormatTime(int ticks)
|
||||
{
|
||||
var seconds = ticks / 25;
|
||||
var minutes = seconds / 60;
|
||||
|
||||
if (minutes >= 60)
|
||||
return "{0:D}:{1:D2}:{2:D2}".F(minutes / 60, minutes % 60, seconds % 60);
|
||||
else
|
||||
return "{0:D2}:{1:D2}".F(minutes, seconds % 60);
|
||||
}
|
||||
}
|
||||
|
||||
[Flags]
|
||||
|
||||
@@ -18,7 +18,7 @@ using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Widgets
|
||||
{
|
||||
class WorldInteractionControllerWidget : Widget
|
||||
public class WorldInteractionControllerWidget : Widget
|
||||
{
|
||||
readonly World world;
|
||||
[ObjectCreator.UseCtor]
|
||||
@@ -134,51 +134,22 @@ 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)
|
||||
{
|
||||
return world.FindUnits(a, b)
|
||||
.Where( x => x.HasTrait<Selectable>() && x.IsVisible(world.LocalPlayer) )
|
||||
.Where( x => x.HasTrait<Selectable>() && world.LocalShroud.IsVisible(x) )
|
||||
.GroupBy(x => (x.Owner == world.LocalPlayer) ? x.Info.Traits.Get<SelectableInfo>().Priority : 0)
|
||||
.OrderByDescending(g => g.Key)
|
||||
.Select( g => g.AsEnumerable() )
|
||||
|
||||
@@ -44,6 +44,7 @@ namespace OpenRA
|
||||
{
|
||||
get { return players.ContainsKey(localPlayerIndex) ? players[localPlayerIndex] : null; }
|
||||
}
|
||||
public readonly Shroud LocalShroud;
|
||||
|
||||
public void SetLocalPlayer(int index)
|
||||
{
|
||||
@@ -51,7 +52,6 @@ namespace OpenRA
|
||||
}
|
||||
|
||||
public readonly Actor WorldActor;
|
||||
|
||||
public readonly Map Map;
|
||||
public readonly TileSet TileSet;
|
||||
|
||||
@@ -98,6 +98,8 @@ namespace OpenRA
|
||||
SharedRandom = new XRandom(orderManager.LobbyInfo.GlobalSettings.RandomSeed);
|
||||
|
||||
WorldActor = CreateActor( "World", new TypeDictionary() );
|
||||
LocalShroud = WorldActor.Trait<Shroud>();
|
||||
|
||||
Queries = new AllQueries(this);
|
||||
|
||||
// Add players
|
||||
@@ -199,11 +201,7 @@ namespace OpenRA
|
||||
|
||||
// hash all the traits that tick
|
||||
foreach (var x in traitDict.ActorsWithTraitMultiple<object>(this))
|
||||
{
|
||||
if (x.Trait is ITraitNotSynced) continue;
|
||||
|
||||
ret += n++*(int) x.Actor.ActorID*Sync.CalculateSyncHash(x.Trait);
|
||||
}
|
||||
|
||||
// Hash the shared rng
|
||||
ret += SharedRandom.Last;
|
||||
|
||||
@@ -15,6 +15,7 @@ using OpenRA.FileFormats;
|
||||
using OpenRA.GameRules;
|
||||
using OpenRA.Support;
|
||||
using OpenRA.Traits;
|
||||
using System;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
@@ -23,7 +24,7 @@ namespace OpenRA
|
||||
public static IEnumerable<Actor> FindUnitsAtMouse(this World world, int2 mouseLocation)
|
||||
{
|
||||
var loc = mouseLocation + Game.viewport.Location;
|
||||
return FindUnits(world, loc, loc).Where(a => a.IsVisible(world.LocalPlayer));
|
||||
return FindUnits(world, loc, loc).Where(a => world.LocalShroud.IsVisible(a));
|
||||
}
|
||||
|
||||
public static IEnumerable<Actor> FindUnits(this World world, float2 a, float2 b)
|
||||
@@ -52,13 +53,8 @@ namespace OpenRA
|
||||
|
||||
public static IEnumerable<int2> FindTilesInCircle(this World world, int2 a, int r)
|
||||
{
|
||||
var min = a - new int2(r, r);
|
||||
var max = a + new int2(r, r);
|
||||
if (min.X < world.Map.XOffset) min.X = world.Map.XOffset;
|
||||
if (min.Y < world.Map.YOffset) min.Y = world.Map.YOffset;
|
||||
if (max.X > world.Map.XOffset + world.Map.Width - 1) max.X = world.Map.XOffset + world.Map.Width - 1;
|
||||
if (max.Y > world.Map.YOffset + world.Map.Height - 1) max.Y = world.Map.YOffset + world.Map.Height - 1;
|
||||
|
||||
var min = world.ClampToWorld(a - new int2(r, r));
|
||||
var max = world.ClampToWorld(a + new int2(r, r));
|
||||
for (var j = min.Y; j <= max.Y; j++)
|
||||
for (var i = min.X; i <= max.X; i++)
|
||||
if (r * r >= (new int2(i, j) - a).LengthSquared)
|
||||
@@ -76,25 +72,9 @@ namespace OpenRA
|
||||
return world.TileSet.Terrain[world.GetTerrainType(cell)];
|
||||
}
|
||||
|
||||
public static bool IsVisible(this Actor a, Player byPlayer) /* must never be relied on in synced code! */
|
||||
{
|
||||
if (byPlayer == null) return true; // Observer
|
||||
if (a.World.LocalPlayer != null && a.World.LocalPlayer.Shroud.Disabled)
|
||||
return true;
|
||||
|
||||
var shroud = a.World.WorldActor.Trait<Shroud>();
|
||||
if (!Shroud.GetVisOrigins(a).Any(o => a.World.Map.IsInMap(o) && shroud.exploredCells[o.X, o.Y])) // covered by shroud
|
||||
return false;
|
||||
|
||||
if (a.TraitsImplementing<IVisibilityModifier>().Any(t => !t.IsVisible(a, byPlayer)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static int2 ClampToWorld( this World world, int2 xy )
|
||||
{
|
||||
return int2.Min(world.Map.BottomRight, int2.Max(world.Map.TopLeft, xy));
|
||||
return xy.Clamp(world.Map.Bounds);
|
||||
}
|
||||
|
||||
public static int2 ChooseRandomEdgeCell(this World w)
|
||||
@@ -103,17 +83,17 @@ namespace OpenRA
|
||||
var edge = w.SharedRandom.Next(2) == 0;
|
||||
|
||||
return new int2(
|
||||
isX ? w.SharedRandom.Next(w.Map.XOffset, w.Map.XOffset + w.Map.Width)
|
||||
: (edge ? w.Map.XOffset : w.Map.XOffset + w.Map.Width),
|
||||
!isX ? w.SharedRandom.Next(w.Map.YOffset, w.Map.YOffset + w.Map.Height)
|
||||
: (edge ? w.Map.YOffset : w.Map.YOffset + w.Map.Height));
|
||||
isX ? w.SharedRandom.Next(w.Map.Bounds.Left, w.Map.Bounds.Right)
|
||||
: (edge ? w.Map.Bounds.Left : w.Map.Bounds.Right),
|
||||
!isX ? w.SharedRandom.Next(w.Map.Bounds.Top, w.Map.Bounds.Bottom)
|
||||
: (edge ? w.Map.Bounds.Top : w.Map.Bounds.Bottom));
|
||||
}
|
||||
|
||||
public static int2 ChooseRandomCell(this World w, Thirdparty.Random r)
|
||||
{
|
||||
return new int2(
|
||||
r.Next(w.Map.XOffset, w.Map.XOffset + w.Map.Width),
|
||||
r.Next(w.Map.YOffset, w.Map.YOffset + w.Map.Height));
|
||||
r.Next(w.Map.Bounds.Left, w.Map.Bounds.Right),
|
||||
r.Next(w.Map.Bounds.Top, w.Map.Bounds.Bottom));
|
||||
}
|
||||
|
||||
public static IEnumerable<CountryInfo> GetCountries(this World w)
|
||||
@@ -134,17 +114,6 @@ namespace OpenRA
|
||||
return new float2(Gauss1D(r, samples), Gauss1D(r, samples));
|
||||
}
|
||||
|
||||
public static string FormatTime(int ticks)
|
||||
{
|
||||
var seconds = ticks / 25;
|
||||
var minutes = seconds / 60;
|
||||
|
||||
if (minutes >= 60)
|
||||
return "{0:D}:{1:D2}:{2:D2}".F(minutes / 60, minutes % 60, seconds % 60);
|
||||
else
|
||||
return "{0:D2}:{1:D2}".F(minutes, seconds % 60);
|
||||
}
|
||||
|
||||
public static bool HasVoice(this Actor a)
|
||||
{
|
||||
return a.Info.Traits.Contains<SelectableInfo>() && a.Info.Traits.Get<SelectableInfo>().Voice != null;
|
||||
|
||||
39
OpenRA.Launcher.Mac/Controller.h
Normal file
39
OpenRA.Launcher.Mac/Controller.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <WebKit/WebKit.h>
|
||||
@class Mod;
|
||||
@class SidebarEntry;
|
||||
@class GameInstall;
|
||||
@class JSBridge;
|
||||
@class Download;
|
||||
@interface Controller : NSObject
|
||||
{
|
||||
SidebarEntry *sidebarItems;
|
||||
GameInstall *game;
|
||||
NSDictionary *allMods;
|
||||
NSMutableDictionary *downloads;
|
||||
BOOL hasMono;
|
||||
|
||||
IBOutlet NSWindow *window;
|
||||
IBOutlet NSOutlineView *outlineView;
|
||||
IBOutlet WebView *webView;
|
||||
}
|
||||
@property(readonly) NSDictionary *allMods;
|
||||
@property(readonly) WebView *webView;
|
||||
|
||||
- (void)launchMod:(NSString *)mod;
|
||||
- (void)populateModInfo;
|
||||
- (SidebarEntry *)sidebarModsTree;
|
||||
- (SidebarEntry *)sidebarOtherTree;
|
||||
|
||||
- (BOOL)registerDownload:(NSString *)key withURL:(NSString *)url filePath:(NSString *)path;
|
||||
- (Download *)downloadWithKey:(NSString *)key;
|
||||
- (BOOL)hasSupportedMono;
|
||||
@end
|
||||
303
OpenRA.Launcher.Mac/Controller.m
Normal file
303
OpenRA.Launcher.Mac/Controller.m
Normal file
@@ -0,0 +1,303 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#import "Controller.h"
|
||||
#import "Mod.h"
|
||||
#import "SidebarEntry.h"
|
||||
#import "GameInstall.h"
|
||||
#import "ImageAndTextCell.h"
|
||||
#import "JSBridge.h"
|
||||
#import "Download.h"
|
||||
|
||||
@implementation Controller
|
||||
@synthesize allMods;
|
||||
@synthesize webView;
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults]
|
||||
registerDefaults:[NSDictionary dictionaryWithObject:[[NSBundle mainBundle] resourcePath]
|
||||
forKey:@"gamepath"]];
|
||||
}
|
||||
|
||||
- (void)awakeFromNib
|
||||
{
|
||||
NSString *gamePath = [[NSUserDefaults standardUserDefaults] stringForKey:@"gamepath"];
|
||||
|
||||
game = [[GameInstall alloc] initWithPath:gamePath];
|
||||
[[JSBridge sharedInstance] setController:self];
|
||||
downloads = [[NSMutableDictionary alloc] init];
|
||||
hasMono = [self hasSupportedMono];
|
||||
if (hasMono)
|
||||
{
|
||||
NSTableColumn *col = [outlineView tableColumnWithIdentifier:@"mods"];
|
||||
ImageAndTextCell *imageAndTextCell = [[[ImageAndTextCell alloc] init] autorelease];
|
||||
[col setDataCell:imageAndTextCell];
|
||||
|
||||
sidebarItems = [[SidebarEntry headerWithTitle:@""] retain];
|
||||
[self populateModInfo];
|
||||
id modsRoot = [self sidebarModsTree];
|
||||
[sidebarItems addChild:modsRoot];
|
||||
//id otherRoot = [self sidebarOtherTree];
|
||||
//[sidebarItems addChild:otherRoot];
|
||||
|
||||
|
||||
[outlineView reloadData];
|
||||
[outlineView expandItem:modsRoot expandChildren:YES];
|
||||
|
||||
if ([[modsRoot children] count] > 0)
|
||||
{
|
||||
id firstMod = [[modsRoot children] objectAtIndex:0];
|
||||
int row = [outlineView rowForItem:firstMod];
|
||||
[outlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];
|
||||
[[webView mainFrame] loadRequest:[NSURLRequest requestWithURL: [firstMod url]]];
|
||||
}
|
||||
|
||||
//[outlineView expandItem:otherRoot expandChildren:YES];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
|
||||
{
|
||||
if (!hasMono)
|
||||
{
|
||||
NSAlert *alert = [NSAlert alertWithMessageText:@"Mono Framework"
|
||||
defaultButton:@"Download Mono"
|
||||
alternateButton:@"Quit"
|
||||
otherButton:nil
|
||||
informativeTextWithFormat:@"OpenRA requires the Mono Framework version 2.6.7 or later."];
|
||||
|
||||
[alert beginSheetModalForWindow:window modalDelegate:self didEndSelector:@selector(monoAlertEnded:code:context:) contextInfo:NULL];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)monoAlertEnded:(NSAlert *)alert
|
||||
code:(int)button
|
||||
context:(void *)v
|
||||
{
|
||||
if (button == NSAlertDefaultReturn)
|
||||
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://www.go-mono.com/mono-downloads/download.html"]];
|
||||
|
||||
[[NSApplication sharedApplication] terminate:self];
|
||||
}
|
||||
|
||||
- (BOOL)hasSupportedMono
|
||||
{
|
||||
if (![[NSFileManager defaultManager] fileExistsAtPath:@"/Library/Frameworks/Mono.framework/Commands/mono"])
|
||||
return NO;
|
||||
|
||||
NSPipe *outPipe = [NSPipe pipe];
|
||||
NSTask *task = [[NSTask alloc] init];
|
||||
[task setLaunchPath:@"/Library/Frameworks/Mono.framework/Commands/mono"];
|
||||
[task setArguments:[NSMutableArray arrayWithObject:@"--version"]];
|
||||
[task setStandardOutput:outPipe];
|
||||
[task setStandardError:[task standardOutput]];
|
||||
[task launch];
|
||||
|
||||
NSData *data = [[outPipe fileHandleForReading] readDataToEndOfFile];
|
||||
[task waitUntilExit];
|
||||
[task release];
|
||||
|
||||
NSString *ret = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
|
||||
|
||||
int major = 0;
|
||||
int minor = 0;
|
||||
int point = 0;
|
||||
sscanf([ret UTF8String], "Mono JIT compiler version %d.%d.%d", &major, &minor, &point);
|
||||
[ret release];
|
||||
|
||||
return (major > 2 ||
|
||||
(major == 2 && minor > 6) ||
|
||||
(major == 2 && minor == 6 && point >= 7));
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[sidebarItems release]; sidebarItems = nil;
|
||||
[downloads release]; downloads = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void)populateModInfo
|
||||
{
|
||||
// Get info for all installed mods
|
||||
[allMods autorelease];
|
||||
allMods = [[game infoForMods:[game installedMods]] retain];
|
||||
}
|
||||
|
||||
- (SidebarEntry *)sidebarModsTree
|
||||
{
|
||||
SidebarEntry *rootItem = [SidebarEntry headerWithTitle:@"MODS"];
|
||||
for (id key in allMods)
|
||||
{
|
||||
id aMod = [allMods objectForKey:key];
|
||||
if ([aMod standalone])
|
||||
{
|
||||
id path = [[game gamePath] stringByAppendingPathComponent:@"mods"];
|
||||
id child = [SidebarEntry entryWithMod:aMod allMods:allMods baseURL:[NSURL URLWithString:path]];
|
||||
[rootItem addChild:child];
|
||||
}
|
||||
}
|
||||
|
||||
return rootItem;
|
||||
}
|
||||
|
||||
- (SidebarEntry *)sidebarOtherTree
|
||||
{
|
||||
SidebarEntry *rootItem = [SidebarEntry headerWithTitle:@"OTHER"];
|
||||
[rootItem addChild:[SidebarEntry entryWithTitle:@"Support" url:nil icon:nil]];
|
||||
[rootItem addChild:[SidebarEntry entryWithTitle:@"Credits" url:nil icon:nil]];
|
||||
|
||||
return rootItem;
|
||||
}
|
||||
|
||||
- (void)launchMod:(NSString *)mod
|
||||
{
|
||||
[game launchMod:mod];
|
||||
}
|
||||
|
||||
- (BOOL)registerDownload:(NSString *)key withURL:(NSString *)url filePath:(NSString *)path;
|
||||
{
|
||||
if ([downloads objectForKey:key] != nil)
|
||||
return NO;
|
||||
|
||||
[downloads setObject:[Download downloadWithURL:url filename:path key:key game:game]
|
||||
forKey:key];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (Download *)downloadWithKey:(NSString *)key
|
||||
{
|
||||
return [downloads objectForKey:key];
|
||||
}
|
||||
|
||||
#pragma mark Sidebar Datasource and Delegate
|
||||
- (NSInteger)outlineView:(NSOutlineView *)anOutlineView numberOfChildrenOfItem:(id)item
|
||||
{
|
||||
// Can be called before awakeFromNib; return nothing
|
||||
if (sidebarItems == nil)
|
||||
return 0;
|
||||
|
||||
// Root item
|
||||
if (item == nil)
|
||||
return [[sidebarItems children] count];
|
||||
|
||||
return [[item children] count];
|
||||
}
|
||||
|
||||
- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item
|
||||
{
|
||||
return (item == nil) ? YES : [[item children] count] != 0;
|
||||
}
|
||||
|
||||
- (id)outlineView:(NSOutlineView *)outlineView
|
||||
child:(NSInteger)index
|
||||
ofItem:(id)item
|
||||
{
|
||||
if (item == nil)
|
||||
return [[sidebarItems children] objectAtIndex:index];
|
||||
|
||||
return [[item children] objectAtIndex:index];
|
||||
}
|
||||
|
||||
-(BOOL)outlineView:(NSOutlineView*)outlineView isGroupItem:(id)item
|
||||
{
|
||||
if (item == nil)
|
||||
return NO;
|
||||
|
||||
return [item isHeader];
|
||||
}
|
||||
|
||||
- (id)outlineView:(NSOutlineView *)outlineView
|
||||
objectValueForTableColumn:(NSTableColumn *)tableColumn
|
||||
byItem:(id)item
|
||||
{
|
||||
return [item title];
|
||||
}
|
||||
|
||||
- (BOOL)outlineView:(NSOutlineView *)outlineView shouldSelectItem:(id)item;
|
||||
{
|
||||
// don't allow headers to be selected
|
||||
if ([item isHeader] || [item url] == nil)
|
||||
return NO;
|
||||
|
||||
[[webView mainFrame] loadRequest:[NSURLRequest requestWithURL:[item url]]];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)outlineView:(NSOutlineView *)olv willDisplayCell:(NSCell*)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
|
||||
{
|
||||
if ([[tableColumn identifier] isEqualToString:@"mods"])
|
||||
{
|
||||
if ([cell isKindOfClass:[ImageAndTextCell class]])
|
||||
{
|
||||
[(ImageAndTextCell*)cell setImage:[item icon]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark WebView delegates
|
||||
- (void)webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)windowObject forFrame:(WebFrame *)frame
|
||||
{
|
||||
[windowObject setValue:[JSBridge sharedInstance] forKey:@"external"];
|
||||
}
|
||||
|
||||
- (void)webView:(WebView *)webView addMessageToConsole:(NSDictionary *)dictionary
|
||||
{
|
||||
NSLog(@"%@",dictionary);
|
||||
}
|
||||
|
||||
|
||||
#pragma mark Application delegates
|
||||
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
|
||||
{
|
||||
int count = 0;
|
||||
for (NSString *key in downloads)
|
||||
if ([[(Download *)[downloads objectForKey:key] status] isEqualToString:@"DOWNLOADING"])
|
||||
count++;
|
||||
|
||||
if (count == 0)
|
||||
return NSTerminateNow;
|
||||
|
||||
NSString *format = count == 1 ? @"1 download is" : [NSString stringWithFormat:@"%d downloads are",count];
|
||||
NSAlert *alert = [NSAlert alertWithMessageText:@"Are you sure you want to quit?"
|
||||
defaultButton:@"Wait"
|
||||
alternateButton:@"Quit"
|
||||
otherButton:nil
|
||||
informativeTextWithFormat:@"%@ in progress and will be cancelled if you quit.", format];
|
||||
|
||||
[alert beginSheetModalForWindow:window modalDelegate:self didEndSelector:@selector(quitAlertEnded:code:context:) contextInfo:NULL];
|
||||
return NSTerminateLater;
|
||||
}
|
||||
|
||||
- (void)quitAlertEnded:(NSAlert *)alert
|
||||
code:(int)button
|
||||
context:(void *)v
|
||||
{
|
||||
NSApplicationTerminateReply reply = (button == NSAlertDefaultReturn) ? NSTerminateCancel : NSTerminateNow;
|
||||
[[NSApplication sharedApplication] replyToApplicationShouldTerminate:reply];
|
||||
}
|
||||
|
||||
- (void)applicationWillTerminate:(NSNotification *)aNotification
|
||||
{
|
||||
// Cancel all in-progress downloads
|
||||
for (NSString *key in downloads)
|
||||
{
|
||||
Download *d = [downloads objectForKey:key];
|
||||
if ([[d status] isEqualToString:@"DOWNLOADING"])
|
||||
[d cancel];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
36
OpenRA.Launcher.Mac/Download.h
Normal file
36
OpenRA.Launcher.Mac/Download.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@class GameInstall;
|
||||
@interface Download : NSObject
|
||||
{
|
||||
NSString *key;
|
||||
NSString *url;
|
||||
NSString *filename;
|
||||
GameInstall *game;
|
||||
NSTask *task;
|
||||
NSString *status;
|
||||
NSString *error;
|
||||
int bytesCompleted;
|
||||
int bytesTotal;
|
||||
}
|
||||
|
||||
@property(readonly) NSString *key;
|
||||
@property(readonly) NSString *status;
|
||||
@property(readonly) int bytesCompleted;
|
||||
@property(readonly) int bytesTotal;
|
||||
@property(readonly) NSString *error;
|
||||
|
||||
+ (id)downloadWithURL:(NSString *)aURL filename:(NSString *)aFilename key:(NSString *)aKey game:(GameInstall *)aGame;
|
||||
- (id)initWithURL:(NSString *)aURL filename:(NSString *)aFilename key:(NSString *)aKey game:(GameInstall *)game;
|
||||
- (BOOL)start;
|
||||
- (BOOL)cancel;
|
||||
- (BOOL)extractToPath:(NSString *)aPath;
|
||||
@end
|
||||
196
OpenRA.Launcher.Mac/Download.m
Normal file
196
OpenRA.Launcher.Mac/Download.m
Normal file
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#import "Download.h"
|
||||
#import "GameInstall.h"
|
||||
#import "JSBridge.h"
|
||||
|
||||
@implementation Download
|
||||
@synthesize key;
|
||||
@synthesize status;
|
||||
@synthesize bytesCompleted;
|
||||
@synthesize bytesTotal;
|
||||
@synthesize error;
|
||||
|
||||
+ (id)downloadWithURL:(NSString *)aURL filename:(NSString *)aFilename key:(NSString *)aKey game:(GameInstall *)aGame
|
||||
{
|
||||
id newObject = [[self alloc] initWithURL:aURL filename:aFilename key:aKey game:aGame];
|
||||
[newObject autorelease];
|
||||
return newObject;
|
||||
}
|
||||
|
||||
- (id)initWithURL:(NSString *)aURL filename:(NSString *)aFilename key:(NSString *)aKey game:(GameInstall *)aGame;
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
url = [aURL retain];
|
||||
filename = [aFilename retain];
|
||||
key = [aKey retain];
|
||||
game = [aGame retain];
|
||||
error = @"";
|
||||
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:filename])
|
||||
{
|
||||
status = @"DOWNLOADED";
|
||||
bytesCompleted = bytesTotal = [[[NSFileManager defaultManager] attributesOfItemAtPath:filename error:NULL] fileSize];
|
||||
}
|
||||
else
|
||||
{
|
||||
status = @"AVAILABLE";
|
||||
bytesCompleted = bytesTotal = -1;
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)start
|
||||
{
|
||||
status = @"DOWNLOADING";
|
||||
task = [game runAsyncUtilityWithArg:[NSString stringWithFormat:@"--download-url=%@,%@",url,filename]
|
||||
delegate:self
|
||||
responseSelector:@selector(downloadResponded:)
|
||||
terminatedSelector:@selector(utilityTerminated:)];
|
||||
[task retain];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)cancel
|
||||
{
|
||||
status = @"ERROR";
|
||||
error = @"Download Cancelled";
|
||||
|
||||
[[NSFileManager defaultManager] removeItemAtPath:filename error:NULL];
|
||||
bytesCompleted = bytesTotal = -1;
|
||||
|
||||
[[JSBridge sharedInstance] notifyDownloadProgress:self];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self
|
||||
name:NSFileHandleReadCompletionNotification
|
||||
object:[[task standardOutput] fileHandleForReading]];
|
||||
[task terminate];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)downloadResponded:(NSNotification *)n
|
||||
{
|
||||
NSData *data = [[n userInfo] valueForKey:NSFileHandleNotificationDataItem];
|
||||
NSString *response = [[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding] autorelease];
|
||||
|
||||
// Response can contain multiple lines, or no lines. Split into lines, and parse each in turn
|
||||
NSArray *lines = [response componentsSeparatedByString:@"\n"];
|
||||
for (NSString *line in lines)
|
||||
{
|
||||
NSRange separator = [line rangeOfString:@":"];
|
||||
if (separator.location == NSNotFound)
|
||||
continue; // We only care about messages of the form key: value
|
||||
|
||||
NSString *type = [line substringToIndex:separator.location];
|
||||
NSString *message = [[line substringFromIndex:separator.location+1]
|
||||
stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||
|
||||
if ([type isEqualToString:@"Error"])
|
||||
{
|
||||
status = @"ERROR";
|
||||
[error autorelease];
|
||||
if ([[message substringToIndex:36] isEqualToString:@"The remote server returned an error:"])
|
||||
error = [[message substringFromIndex:37] retain];
|
||||
else
|
||||
error = [message retain];
|
||||
}
|
||||
|
||||
else if ([type isEqualToString:@"Status"])
|
||||
{
|
||||
if ([message isEqualToString:@"Completed"])
|
||||
{
|
||||
status = @"DOWNLOADED";
|
||||
}
|
||||
|
||||
// Parse download status info
|
||||
int done,total;
|
||||
if (sscanf([message UTF8String], "%*d%% %d/%d bytes", &done, &total) == 2)
|
||||
{
|
||||
bytesCompleted = done;
|
||||
bytesTotal = total;
|
||||
}
|
||||
}
|
||||
}
|
||||
[[JSBridge sharedInstance] notifyDownloadProgress:self];
|
||||
|
||||
// Keep reading
|
||||
if ([n object] != nil)
|
||||
[[n object] readInBackgroundAndNotify];
|
||||
}
|
||||
|
||||
- (BOOL)extractToPath:(NSString *)aPath
|
||||
{
|
||||
status = @"EXTRACTING";
|
||||
task = [game runAsyncUtilityWithArg:[NSString stringWithFormat:@"--extract-zip=%@,%@",filename,aPath]
|
||||
delegate:self
|
||||
responseSelector:@selector(extractResponded:)
|
||||
terminatedSelector:@selector(utilityTerminated:)];
|
||||
[task retain];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)extractResponded:(NSNotification *)n
|
||||
{
|
||||
NSData *data = [[n userInfo] valueForKey:NSFileHandleNotificationDataItem];
|
||||
NSString *response = [[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding] autorelease];
|
||||
|
||||
// Response can contain multiple lines, or no lines. Split into lines, and parse each in turn
|
||||
NSArray *lines = [response componentsSeparatedByString:@"\n"];
|
||||
for (NSString *line in lines)
|
||||
{
|
||||
NSLog(@"%@",line);
|
||||
NSRange separator = [line rangeOfString:@":"];
|
||||
if (separator.location == NSNotFound)
|
||||
continue; // We only care about messages of the form key: value
|
||||
|
||||
NSString *type = [line substringToIndex:separator.location];
|
||||
NSString *message = [[line substringFromIndex:separator.location+1]
|
||||
stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||
|
||||
if ([type isEqualToString:@"Error"])
|
||||
{
|
||||
status = @"ERROR";
|
||||
[error autorelease];
|
||||
error = [message retain];
|
||||
}
|
||||
|
||||
else if ([type isEqualToString:@"Status"])
|
||||
{
|
||||
if ([message isEqualToString:@"Completed"])
|
||||
{
|
||||
status = @"EXTRACTED";
|
||||
}
|
||||
}
|
||||
}
|
||||
[[JSBridge sharedInstance] notifyExtractProgress:self];
|
||||
|
||||
// Keep reading
|
||||
if ([n object] != nil)
|
||||
[[n object] readInBackgroundAndNotify];
|
||||
}
|
||||
|
||||
- (void)utilityTerminated:(NSNotification *)n
|
||||
{
|
||||
NSLog(@"download terminated");
|
||||
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
||||
[nc removeObserver:self name:NSFileHandleReadCompletionNotification object:[[task standardOutput] fileHandleForReading]];
|
||||
[nc removeObserver:self name:NSTaskDidTerminateNotification object:task];
|
||||
[task release]; task = nil;
|
||||
|
||||
if (status == @"ERROR")
|
||||
{
|
||||
[[NSFileManager defaultManager] removeItemAtPath:filename error:NULL];
|
||||
bytesCompleted = bytesTotal = -1;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
File diff suppressed because it is too large
Load Diff
29
OpenRA.Launcher.Mac/GameInstall.h
Normal file
29
OpenRA.Launcher.Mac/GameInstall.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@class Mod;
|
||||
@class Controller;
|
||||
@interface GameInstall : NSObject {
|
||||
NSString *gamePath;
|
||||
Controller *controller;
|
||||
NSMutableDictionary *downloadTasks;
|
||||
}
|
||||
@property(readonly) NSString *gamePath;
|
||||
|
||||
-(id)initWithPath:(NSString *)path;
|
||||
-(void)launchMod:(NSString *)mod;
|
||||
- (NSString *)runUtilityQuery:(NSString *)arg;
|
||||
- (NSArray *)installedMods;
|
||||
- (NSDictionary *)infoForMods:(NSArray *)mods;
|
||||
- (NSTask *)runAsyncUtilityWithArg:(NSString *)arg
|
||||
delegate:(id)object
|
||||
responseSelector:(SEL)response
|
||||
terminatedSelector:(SEL)terminated;
|
||||
@end
|
||||
178
OpenRA.Launcher.Mac/GameInstall.m
Normal file
178
OpenRA.Launcher.Mac/GameInstall.m
Normal file
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#import "GameInstall.h"
|
||||
#import "Controller.h"
|
||||
#import "Mod.h"
|
||||
|
||||
@implementation GameInstall
|
||||
@synthesize gamePath;
|
||||
|
||||
-(id)initWithPath:(NSString *)path
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
gamePath = [path retain];
|
||||
downloadTasks = [[NSMutableDictionary alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[gamePath release]; gamePath = nil;
|
||||
[downloadTasks release]; downloadTasks = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (NSArray *)installedMods
|
||||
{
|
||||
id raw = [self runUtilityQuery:@"-l"];
|
||||
id mods = [raw stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||
return [mods componentsSeparatedByString:@"\n"];
|
||||
}
|
||||
|
||||
- (NSDictionary *)infoForMods:(NSArray *)mods
|
||||
{
|
||||
id query = [NSString stringWithFormat:@"-i=%@",[mods componentsJoinedByString:@","]];
|
||||
NSArray *lines = [[self runUtilityQuery:query] componentsSeparatedByString:@"\n"];
|
||||
|
||||
NSMutableDictionary *ret = [NSMutableDictionary dictionary];
|
||||
NSMutableDictionary *fields = nil;
|
||||
NSString *current = nil;
|
||||
for (id l in lines)
|
||||
{
|
||||
NSString *line = [l stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||
if (line == nil || [line length] == 0)
|
||||
continue;
|
||||
|
||||
id kv = [line componentsSeparatedByString:@":"];
|
||||
if ([kv count] < 2)
|
||||
continue;
|
||||
|
||||
id key = [kv objectAtIndex:0];
|
||||
id value = [kv objectAtIndex:1];
|
||||
|
||||
if ([key isEqualToString:@"Error"])
|
||||
{
|
||||
NSLog(@"Error: %@",value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ([key isEqualToString:@"Mod"])
|
||||
{
|
||||
// Commit prev mod
|
||||
if (current != nil)
|
||||
{
|
||||
id path = [gamePath stringByAppendingPathComponent:[NSString stringWithFormat:@"mods/%@",current]];
|
||||
[ret setObject:[Mod modWithId:current fields:fields baseURL:[NSURL URLWithString:path]] forKey:current];
|
||||
}
|
||||
NSLog(@"Parsing mod %@",value);
|
||||
current = value;
|
||||
fields = [NSMutableDictionary dictionary];
|
||||
}
|
||||
|
||||
if (fields != nil)
|
||||
[fields setObject:[value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]
|
||||
forKey:key];
|
||||
}
|
||||
if (current != nil)
|
||||
{
|
||||
id path = [gamePath stringByAppendingPathComponent:[NSString stringWithFormat:@"mods/%@",current]];
|
||||
[ret setObject:[Mod modWithId:current fields:fields baseURL:[NSURL URLWithString:path]] forKey:current];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
-(void)launchMod:(NSString *)mod
|
||||
{
|
||||
// Use LaunchServices because neither NSTask or NSWorkspace support Info.plist _and_ arguments pre-10.6
|
||||
NSString *path = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"OpenRA.app/Contents/MacOS/OpenRA"];
|
||||
|
||||
// First argument is the directory to run in
|
||||
// Second...Nth arguments are passed to OpenRA.Game.exe
|
||||
// Launcher wrapper sets mono --debug, gl renderer and support dir.
|
||||
NSArray *args = [NSArray arrayWithObjects:gamePath,
|
||||
[NSString stringWithFormat:@"Game.Mods=%@",mod],
|
||||
nil];
|
||||
|
||||
FSRef appRef;
|
||||
CFURLGetFSRef((CFURLRef)[NSURL URLWithString:path], &appRef);
|
||||
|
||||
// Set the launch parameters
|
||||
LSApplicationParameters params;
|
||||
params.version = 0;
|
||||
params.flags = kLSLaunchDefaults;
|
||||
params.application = &appRef;
|
||||
params.asyncLaunchRefCon = NULL;
|
||||
params.environment = NULL; // CFDictionaryRef of environment variables; could be useful
|
||||
params.argv = (CFArrayRef)args;
|
||||
params.initialEvent = NULL;
|
||||
|
||||
ProcessSerialNumber psn;
|
||||
OSStatus err = LSOpenApplication(¶ms, &psn);
|
||||
|
||||
// Bring the game window to the front
|
||||
if (err == noErr)
|
||||
SetFrontProcess(&psn);
|
||||
}
|
||||
|
||||
- (NSString *)runUtilityQuery:(NSString *)arg
|
||||
{
|
||||
NSPipe *outPipe = [NSPipe pipe];
|
||||
NSMutableArray *taskArgs = [NSMutableArray arrayWithObject:@"OpenRA.Utility.exe"];
|
||||
[taskArgs addObject:arg];
|
||||
|
||||
NSTask *task = [[NSTask alloc] init];
|
||||
[task setCurrentDirectoryPath:gamePath];
|
||||
[task setLaunchPath:@"/Library/Frameworks/Mono.framework/Commands/mono"];
|
||||
[task setArguments:taskArgs];
|
||||
[task setStandardOutput:outPipe];
|
||||
[task setStandardError:[task standardOutput]];
|
||||
[task launch];
|
||||
NSData *data = [[outPipe fileHandleForReading] readDataToEndOfFile];
|
||||
[task waitUntilExit];
|
||||
[task release];
|
||||
|
||||
return [[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding] autorelease];
|
||||
}
|
||||
|
||||
- (NSTask *)runAsyncUtilityWithArg:(NSString *)arg
|
||||
delegate:(id)object
|
||||
responseSelector:(SEL)response
|
||||
terminatedSelector:(SEL)terminated
|
||||
{
|
||||
NSTask *task = [[[NSTask alloc] init] autorelease];
|
||||
NSPipe *pipe = [NSPipe pipe];
|
||||
|
||||
NSMutableArray *taskArgs = [NSMutableArray arrayWithObject:@"OpenRA.Utility.exe"];
|
||||
[taskArgs addObject:arg];
|
||||
|
||||
[task setCurrentDirectoryPath:gamePath];
|
||||
[task setLaunchPath:@"/Library/Frameworks/Mono.framework/Commands/mono"];
|
||||
[task setArguments:taskArgs];
|
||||
[task setStandardOutput:pipe];
|
||||
|
||||
NSFileHandle *readHandle = [pipe fileHandleForReading];
|
||||
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
||||
[nc addObserver:object
|
||||
selector:response
|
||||
name:NSFileHandleReadCompletionNotification
|
||||
object:readHandle];
|
||||
[nc addObserver:object
|
||||
selector:terminated
|
||||
name:NSTaskDidTerminateNotification
|
||||
object:task];
|
||||
[task launch];
|
||||
[readHandle readInBackgroundAndNotify];
|
||||
return task;
|
||||
}
|
||||
|
||||
@end
|
||||
62
OpenRA.Launcher.Mac/ImageAndTextCell.h
Executable file
62
OpenRA.Launcher.Mac/ImageAndTextCell.h
Executable file
@@ -0,0 +1,62 @@
|
||||
//
|
||||
// File: ImageAndTextCell.h
|
||||
//
|
||||
// Abstract: Subclass of NSTextFieldCell which can display text and an image simultaneously.
|
||||
//
|
||||
// Version: 1.0
|
||||
//
|
||||
// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. ("Apple")
|
||||
// in consideration of your agreement to the following terms, and your use,
|
||||
// installation, modification or redistribution of this Apple software
|
||||
// constitutes acceptance of these terms. If you do not agree with these
|
||||
// terms, please do not use, install, modify or redistribute this Apple
|
||||
// software.
|
||||
//
|
||||
// In consideration of your agreement to abide by the following terms, and
|
||||
// subject to these terms, Apple grants you a personal, non - exclusive
|
||||
// license, under Apple's copyrights in this original Apple software ( the
|
||||
// "Apple Software" ), to use, reproduce, modify and redistribute the Apple
|
||||
// Software, with or without modifications, in source and / or binary forms;
|
||||
// provided that if you redistribute the Apple Software in its entirety and
|
||||
// without modifications, you must retain this notice and the following text
|
||||
// and disclaimers in all such redistributions of the Apple Software. Neither
|
||||
// the name, trademarks, service marks or logos of Apple Inc. may be used to
|
||||
// endorse or promote products derived from the Apple Software without specific
|
||||
// prior written permission from Apple. Except as expressly stated in this
|
||||
// notice, no other rights or licenses, express or implied, are granted by
|
||||
// Apple herein, including but not limited to any patent rights that may be
|
||||
// infringed by your derivative works or by other works in which the Apple
|
||||
// Software may be incorporated.
|
||||
//
|
||||
// The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
|
||||
// WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
|
||||
// WARRANTIES OF NON - INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
|
||||
// PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION
|
||||
// ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
//
|
||||
// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
|
||||
// CONSEQUENTIAL DAMAGES ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION ) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION
|
||||
// AND / OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER
|
||||
// UNDER THEORY OF CONTRACT, TORT ( INCLUDING NEGLIGENCE ), STRICT LIABILITY OR
|
||||
// OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (C) 2007 Apple Inc. All Rights Reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface ImageAndTextCell : NSTextFieldCell
|
||||
{
|
||||
@private
|
||||
NSImage *image;
|
||||
}
|
||||
|
||||
- (void)setImage:(NSImage *)anImage;
|
||||
- (NSImage*)image;
|
||||
|
||||
- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView;
|
||||
- (NSSize)cellSize;
|
||||
|
||||
@end
|
||||
252
OpenRA.Launcher.Mac/ImageAndTextCell.m
Executable file
252
OpenRA.Launcher.Mac/ImageAndTextCell.m
Executable file
@@ -0,0 +1,252 @@
|
||||
//
|
||||
// File: ImageAndTextCell.m
|
||||
//
|
||||
// Abstract: Subclass of NSTextFieldCell which can display text and an image simultaneously.
|
||||
//
|
||||
// Version: 1.0
|
||||
//
|
||||
// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. ("Apple")
|
||||
// in consideration of your agreement to the following terms, and your use,
|
||||
// installation, modification or redistribution of this Apple software
|
||||
// constitutes acceptance of these terms. If you do not agree with these
|
||||
// terms, please do not use, install, modify or redistribute this Apple
|
||||
// software.
|
||||
//
|
||||
// In consideration of your agreement to abide by the following terms, and
|
||||
// subject to these terms, Apple grants you a personal, non - exclusive
|
||||
// license, under Apple's copyrights in this original Apple software ( the
|
||||
// "Apple Software" ), to use, reproduce, modify and redistribute the Apple
|
||||
// Software, with or without modifications, in source and / or binary forms;
|
||||
// provided that if you redistribute the Apple Software in its entirety and
|
||||
// without modifications, you must retain this notice and the following text
|
||||
// and disclaimers in all such redistributions of the Apple Software. Neither
|
||||
// the name, trademarks, service marks or logos of Apple Inc. may be used to
|
||||
// endorse or promote products derived from the Apple Software without specific
|
||||
// prior written permission from Apple. Except as expressly stated in this
|
||||
// notice, no other rights or licenses, express or implied, are granted by
|
||||
// Apple herein, including but not limited to any patent rights that may be
|
||||
// infringed by your derivative works or by other works in which the Apple
|
||||
// Software may be incorporated.
|
||||
//
|
||||
// The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
|
||||
// WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
|
||||
// WARRANTIES OF NON - INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
|
||||
// PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION
|
||||
// ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
//
|
||||
// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
|
||||
// CONSEQUENTIAL DAMAGES ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION ) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION
|
||||
// AND / OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER
|
||||
// UNDER THEORY OF CONTRACT, TORT ( INCLUDING NEGLIGENCE ), STRICT LIABILITY OR
|
||||
// OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (C) 2007 Apple Inc. All Rights Reserved.
|
||||
//
|
||||
|
||||
#import "ImageAndTextCell.h"
|
||||
//#import "BaseNode.h"
|
||||
|
||||
@implementation ImageAndTextCell
|
||||
|
||||
#define kIconImageSize 16.0
|
||||
|
||||
#define kImageOriginXOffset 3
|
||||
#define kImageOriginYOffset 1
|
||||
|
||||
#define kTextOriginXOffset 2
|
||||
#define kTextOriginYOffset 2
|
||||
#define kTextHeightAdjust 4
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// init:
|
||||
// -------------------------------------------------------------------------------
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
// we want a smaller font
|
||||
[self setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// dealloc:
|
||||
// -------------------------------------------------------------------------------
|
||||
- (void)dealloc
|
||||
{
|
||||
[image release];
|
||||
image = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// copyWithZone:zone
|
||||
// -------------------------------------------------------------------------------
|
||||
- (id)copyWithZone:(NSZone*)zone
|
||||
{
|
||||
ImageAndTextCell *cell = (ImageAndTextCell*)[super copyWithZone:zone];
|
||||
cell->image = [image retain];
|
||||
return cell;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// setImage:anImage
|
||||
// -------------------------------------------------------------------------------
|
||||
- (void)setImage:(NSImage*)anImage
|
||||
{
|
||||
if (anImage != image)
|
||||
{
|
||||
[image autorelease];
|
||||
image = [anImage retain];
|
||||
[image setSize:NSMakeSize(kIconImageSize, kIconImageSize)];
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// image:
|
||||
// -------------------------------------------------------------------------------
|
||||
- (NSImage*)image
|
||||
{
|
||||
return image;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// isGroupCell:
|
||||
// -------------------------------------------------------------------------------
|
||||
- (BOOL)isGroupCell
|
||||
{
|
||||
return ([self image] == nil && [[self title] length] > 0);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// titleRectForBounds:cellRect
|
||||
//
|
||||
// Returns the proper bound for the cell's title while being edited
|
||||
// -------------------------------------------------------------------------------
|
||||
- (NSRect)titleRectForBounds:(NSRect)cellRect
|
||||
{
|
||||
// the cell has an image: draw the normal item cell
|
||||
NSSize imageSize;
|
||||
NSRect imageFrame;
|
||||
|
||||
imageSize = [image size];
|
||||
NSDivideRect(cellRect, &imageFrame, &cellRect, 3 + imageSize.width, NSMinXEdge);
|
||||
|
||||
imageFrame.origin.x += kImageOriginXOffset;
|
||||
imageFrame.origin.y -= kImageOriginYOffset;
|
||||
imageFrame.size = imageSize;
|
||||
|
||||
imageFrame.origin.y += ceil((cellRect.size.height - imageFrame.size.height) / 2);
|
||||
|
||||
NSRect newFrame = cellRect;
|
||||
newFrame.origin.x += kTextOriginXOffset;
|
||||
newFrame.origin.y += kTextOriginYOffset;
|
||||
newFrame.size.height -= kTextHeightAdjust;
|
||||
|
||||
return newFrame;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// editWithFrame:inView:editor:delegate:event
|
||||
// -------------------------------------------------------------------------------
|
||||
- (void)editWithFrame:(NSRect)aRect inView:(NSView*)controlView editor:(NSText*)textObj delegate:(id)anObject event:(NSEvent*)theEvent
|
||||
{
|
||||
NSRect textFrame = [self titleRectForBounds:aRect];
|
||||
[super editWithFrame:textFrame inView:controlView editor:textObj delegate:anObject event:theEvent];
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// selectWithFrame:inView:editor:delegate:event:start:length
|
||||
// -------------------------------------------------------------------------------
|
||||
- (void)selectWithFrame:(NSRect)aRect inView:(NSView*)controlView editor:(NSText*)textObj delegate:(id)anObject start:(NSInteger)selStart length:(NSInteger)selLength
|
||||
{
|
||||
NSRect textFrame = [self titleRectForBounds:aRect];
|
||||
[super selectWithFrame:textFrame inView:controlView editor:textObj delegate:anObject start:selStart length:selLength];
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// drawWithFrame:cellFrame:controlView:
|
||||
// -------------------------------------------------------------------------------
|
||||
- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView
|
||||
{
|
||||
if (image != nil)
|
||||
{
|
||||
// the cell has an image: draw the normal item cell
|
||||
NSSize imageSize;
|
||||
NSRect imageFrame;
|
||||
|
||||
imageSize = [image size];
|
||||
NSDivideRect(cellFrame, &imageFrame, &cellFrame, 3 + imageSize.width, NSMinXEdge);
|
||||
|
||||
imageFrame.origin.x += kImageOriginXOffset;
|
||||
imageFrame.origin.y -= kImageOriginYOffset;
|
||||
imageFrame.size = imageSize;
|
||||
|
||||
if ([controlView isFlipped])
|
||||
imageFrame.origin.y += ceil((cellFrame.size.height + imageFrame.size.height) / 2);
|
||||
else
|
||||
imageFrame.origin.y += ceil((cellFrame.size.height - imageFrame.size.height) / 2);
|
||||
[image compositeToPoint:imageFrame.origin operation:NSCompositeSourceOver];
|
||||
|
||||
NSRect newFrame = cellFrame;
|
||||
newFrame.origin.x += kTextOriginXOffset;
|
||||
newFrame.origin.y += kTextOriginYOffset;
|
||||
newFrame.size.height -= kTextHeightAdjust;
|
||||
[super drawWithFrame:newFrame inView:controlView];
|
||||
}
|
||||
else
|
||||
{
|
||||
if ([self isGroupCell])
|
||||
{
|
||||
// Center the text in the cellFrame, and call super to do thew ork of actually drawing.
|
||||
CGFloat yOffset = floor((NSHeight(cellFrame) - [[self attributedStringValue] size].height) / 2.0);
|
||||
cellFrame.origin.y += yOffset;
|
||||
cellFrame.size.height -= (kTextOriginYOffset*yOffset);
|
||||
[super drawWithFrame:cellFrame inView:controlView];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// cellSize:
|
||||
// -------------------------------------------------------------------------------
|
||||
- (NSSize)cellSize
|
||||
{
|
||||
NSSize cellSize = [super cellSize];
|
||||
cellSize.width += (image ? [image size].width : 0) + 3;
|
||||
return cellSize;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// hitTestForEvent:
|
||||
//
|
||||
// In 10.5, we need you to implement this method for blocking drag and drop of a given cell.
|
||||
// So NSCell hit testing will determine if a row can be dragged or not.
|
||||
//
|
||||
// NSTableView calls this cell method when starting a drag, if the hit cell returns
|
||||
// NSCellHitTrackableArea, the particular row will be tracked instead of dragged.
|
||||
//
|
||||
// -------------------------------------------------------------------------------
|
||||
/*
|
||||
- (NSUInteger)hitTestForEvent:(NSEvent *)event inRect:(NSRect)cellFrame ofView:(NSView *)controlView
|
||||
{
|
||||
NSInteger result = NSCellHitContentArea;
|
||||
|
||||
NSOutlineView* hostingOutlineView = (NSOutlineView*)[self controlView];
|
||||
if (hostingOutlineView)
|
||||
{
|
||||
NSInteger selectedRow = [hostingOutlineView selectedRow];
|
||||
BaseNode* node = [[hostingOutlineView itemAtRow:selectedRow] representedObject];
|
||||
|
||||
if (![node isDraggable]) // is the node isDraggable (i.e. non-file system based objects)
|
||||
result = NSCellHitTrackableArea;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
*/
|
||||
@end
|
||||
|
||||
24
OpenRA.Launcher.Mac/JSBridge.h
Normal file
24
OpenRA.Launcher.Mac/JSBridge.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@class Controller;
|
||||
@class Download;
|
||||
@interface JSBridge : NSObject {
|
||||
Controller *controller;
|
||||
NSDictionary *methods;
|
||||
}
|
||||
@property(readonly) NSDictionary *methods;
|
||||
|
||||
+ (JSBridge *)sharedInstance;
|
||||
- (void)setController:(Controller *)aController;
|
||||
- (void)notifyDownloadProgress:(Download *)download;
|
||||
- (void)notifyExtractProgress:(Download *)download;
|
||||
@end
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user