Compare commits
174 Commits
release-20
...
release-20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
77e795cfd4 | ||
|
|
94f800dc8c | ||
|
|
808baa6afd | ||
|
|
2a67fb39a3 | ||
|
|
fc455ba9e2 | ||
|
|
62baeb38a6 | ||
|
|
43a98b4cbd | ||
|
|
2f57c6c33c | ||
|
|
47f2a721b3 | ||
|
|
1f912d94d2 | ||
|
|
ad383170d5 | ||
|
|
399f554316 | ||
|
|
985cd6f7ea | ||
|
|
338093b710 | ||
|
|
76b94cc7f3 | ||
|
|
885068f89d | ||
|
|
886ae8786e | ||
|
|
6bd430fbc2 | ||
|
|
f0ff1c12ed | ||
|
|
02e1cc6172 | ||
|
|
c1c1e30203 | ||
|
|
83e80cd9fd | ||
|
|
646ca0f629 | ||
|
|
02e044dd8b | ||
|
|
a1f7e16085 | ||
|
|
f94b44574d | ||
|
|
2842ea42d7 | ||
|
|
0051d0ce08 | ||
|
|
1c7c329f1d | ||
|
|
4d368c1ec1 | ||
|
|
c504b2a9ae | ||
|
|
b9f08b4607 | ||
|
|
5897230226 | ||
|
|
f26b0f1251 | ||
|
|
7bc4d205fe | ||
|
|
71d4e29483 | ||
|
|
0e082183e3 | ||
|
|
00bce1266f | ||
|
|
09f0242059 | ||
|
|
aa14f1b0a2 | ||
|
|
3cf6148c03 | ||
|
|
eddda3ecca | ||
|
|
ec001a608e | ||
|
|
07ca72127f | ||
|
|
246b25f008 | ||
|
|
0bca700bff | ||
|
|
0d286e12b2 | ||
|
|
811acc5a58 | ||
|
|
265faa3452 | ||
|
|
bc51d6638d | ||
|
|
60a27f9f83 | ||
|
|
a7cfaff96c | ||
|
|
d957a5a15e | ||
|
|
026a27296c | ||
|
|
f7c2043e06 | ||
|
|
4efe8d091c | ||
|
|
97e810d753 | ||
|
|
7ed82fa4c7 | ||
|
|
32b4402ba0 | ||
|
|
897c0f01f0 | ||
|
|
b21b9c9762 | ||
|
|
5bcc83bc0c | ||
|
|
509662d8a6 | ||
|
|
fd171d842e | ||
|
|
9258face3c | ||
|
|
41e5032d48 | ||
|
|
6006dbd235 | ||
|
|
b7e7ff7fc0 | ||
|
|
6d98635e94 | ||
|
|
46762140a5 | ||
|
|
09cdf3b257 | ||
|
|
033e469bea | ||
|
|
7e680b9c02 | ||
|
|
a56d367f60 | ||
|
|
bd2629196a | ||
|
|
011f566c6f | ||
|
|
161907b852 | ||
|
|
1576101a2c | ||
|
|
67ba3e53f2 | ||
|
|
52b061a8a8 | ||
|
|
5755f4048d | ||
|
|
b1b210ea6d | ||
|
|
fc8f1d40c5 | ||
|
|
5d83a5a7d6 | ||
|
|
8c24e87de2 | ||
|
|
13c4f16272 | ||
|
|
20a33b8411 | ||
|
|
51fcb55b22 | ||
|
|
8e7469e194 | ||
|
|
7e0617075f | ||
|
|
4ff6ba8c37 | ||
|
|
958a72aaf8 | ||
|
|
e7df117892 | ||
|
|
57d49d0aeb | ||
|
|
ee86b5f45f | ||
|
|
ba0e3130af | ||
|
|
64427dd1a6 | ||
|
|
7412669d03 | ||
|
|
ec8e9f537d | ||
|
|
9c71d555c1 | ||
|
|
0f191484d7 | ||
|
|
4be5979b90 | ||
|
|
6bd092f192 | ||
|
|
bd6bcda6d0 | ||
|
|
f12deca9ca | ||
|
|
5ea82b4e5e | ||
|
|
2d210a97df | ||
|
|
f03a100115 | ||
|
|
1e30684782 | ||
|
|
abb45197b1 | ||
|
|
a7935f6166 | ||
|
|
7b75a9c2f7 | ||
|
|
9b694f6044 | ||
|
|
0a75019aa0 | ||
|
|
d3e41b6d50 | ||
|
|
18f3e1f57b | ||
|
|
1760f8acd6 | ||
|
|
4154553318 | ||
|
|
e5e8e64ace | ||
|
|
0ae58c10ad | ||
|
|
89ea810cbe | ||
|
|
f6cf35c99c | ||
|
|
5fbaeabb6d | ||
|
|
581907f53a | ||
|
|
7cf4be9d78 | ||
|
|
bdf9f5e201 | ||
|
|
b26b1f410f | ||
|
|
ce69abe1f2 | ||
|
|
b3d2b36875 | ||
|
|
f28b37323f | ||
|
|
7c82ab60e8 | ||
|
|
d14fbd0f84 | ||
|
|
c567f5cbdd | ||
|
|
51a9831fc2 | ||
|
|
4d5777cbc9 | ||
|
|
a6a835d95f | ||
|
|
e16be14ec7 | ||
|
|
11939d3af1 | ||
|
|
feb133c2eb | ||
|
|
f6361b031b | ||
|
|
36967951e6 | ||
|
|
012a9d71ba | ||
|
|
cff369850c | ||
|
|
136b4c0fa9 | ||
|
|
aae2459d0b | ||
|
|
d47ba1d135 | ||
|
|
133cffff24 | ||
|
|
52f6c993d5 | ||
|
|
21eecb048d | ||
|
|
b97398a671 | ||
|
|
a285c908db | ||
|
|
35b39162ff | ||
|
|
0b5b6adc7c | ||
|
|
5357eb6f29 | ||
|
|
e274ac5ff8 | ||
|
|
f8e39bd142 | ||
|
|
48881f4e73 | ||
|
|
d2eb56183d | ||
|
|
afd75c7f55 | ||
|
|
6d1551c9fd | ||
|
|
a015b0990b | ||
|
|
6dd08bbc98 | ||
|
|
343616e924 | ||
|
|
91242a832f | ||
|
|
1c53bfed11 | ||
|
|
e5e7d037a3 | ||
|
|
2a301392c6 | ||
|
|
e35bb8ea95 | ||
|
|
7a4002ff08 | ||
|
|
523fe20255 | ||
|
|
31e0c8b2e3 | ||
|
|
7c37d1cfcc | ||
|
|
8e76a109bd | ||
|
|
ba9b18ccb7 |
9
.gitignore
vendored
9
.gitignore
vendored
@@ -70,11 +70,4 @@ StyleCopViolations.xml
|
||||
|
||||
# SublimeText
|
||||
*.sublime-project
|
||||
*.sublime-workspace
|
||||
|
||||
# NUnit
|
||||
/TestResult.xml
|
||||
/lib/
|
||||
|
||||
# Support directory
|
||||
/Support
|
||||
*.sublime-workspace
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"name": "OpenRA"
|
||||
, "files": [ { "git": 1 } ]
|
||||
, "build": {
|
||||
"directory": "."
|
||||
, "build": "make all"
|
||||
, "clean": "make clean"
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
# see travis-ci.org for details
|
||||
|
||||
language: csharp
|
||||
mono: 4.2.1
|
||||
mono: 4.0.0
|
||||
|
||||
# http://docs.travis-ci.com/user/migrating-from-legacy
|
||||
sudo: false
|
||||
@@ -28,14 +28,12 @@ env:
|
||||
# Run the build script
|
||||
# Check source code with StyleCop
|
||||
# call OpenRA to check for YAML errors
|
||||
# Run the NUnit tests
|
||||
script:
|
||||
- travis_retry make all-dependencies
|
||||
- make all SDK="-sdk:4.0"
|
||||
- make all
|
||||
- make check
|
||||
- make check-scripts
|
||||
- make test
|
||||
- make nunit
|
||||
|
||||
# Automatically update the trait documentation and Lua API
|
||||
after_success:
|
||||
|
||||
17
AUTHORS
17
AUTHORS
@@ -55,7 +55,6 @@ Also thanks to:
|
||||
* Eric Bajumpaa (SteelPhase)
|
||||
* Evgeniy Sergeev (evgeniysergeev)
|
||||
* Fahrradkette
|
||||
* Florian Wiesbauer (FiveAces)
|
||||
* Frank Razenberg (zzattack)
|
||||
* Gareth Needham (Ripley`)
|
||||
* Glen Anderson (GlenAnderson)
|
||||
@@ -76,12 +75,9 @@ Also thanks to:
|
||||
* Jeff Harris (jeff_1amstudios)
|
||||
* Jes
|
||||
* Joakim Lindberg (booom3)
|
||||
* John Turner (whinis)
|
||||
* Jonas A. Lind (SoScared)
|
||||
* Joppy Furr
|
||||
* Kanar
|
||||
* Kenny Hoxworth (hoxworth)
|
||||
* Kevin Azzam (ChaoticMind)
|
||||
* Krishnakanth Mallik
|
||||
* Kyrre Soerensen (zypres)
|
||||
* Lawrence Wang
|
||||
@@ -94,7 +90,6 @@ Also thanks to:
|
||||
* Matthijs Benschop (Nerdie)
|
||||
* Max621
|
||||
* Max Ugrumov (katzsmile)
|
||||
* Michael Rätzel
|
||||
* Michael Sztolcman (s1w_)
|
||||
* Mustafa Alperen Seki (MustaphaTR)
|
||||
* Neil Shivkar (havok13888)
|
||||
@@ -106,16 +101,12 @@ Also thanks to:
|
||||
* Paul Dovydaitis (pdovy)
|
||||
* Pavlos Touboulidis (pav)
|
||||
* Pizzaoverhead
|
||||
* Piët Delport (pjdelport)
|
||||
* Psydev
|
||||
* Raphael Vogt (TheRaffy, Yellow)
|
||||
* Raymond Bedrossian (Squiggles211)
|
||||
* Raymond Martineau (mart0258)
|
||||
* Riderr3
|
||||
* riiga
|
||||
* Rikhardur Bjarni Einarsson (WolfGaming)
|
||||
* Sascha Biedermann (bidifx)
|
||||
* Sean Hunt (coppro)
|
||||
* Sebastien Kerguen (xanax)
|
||||
* Shawn Collins (UberWaffe)
|
||||
* Simon Verbeke (Saticmotion)
|
||||
@@ -148,8 +139,11 @@ distributed under the CC BY-SA 3.0 license.
|
||||
Using SharpFont created by Robert Rouhani and
|
||||
distributed under the MIT license.
|
||||
|
||||
Using SDL2-CS and OpenAL-CS created by Ethan
|
||||
Lee and released under the zlib license.
|
||||
Using the Open Toolkit distributed under the
|
||||
MIT license.
|
||||
|
||||
Using SDL2# created by Ethan Lee and released
|
||||
under the zlib license.
|
||||
|
||||
Using Eluant created by Chris Howie and released
|
||||
under the MIT license.
|
||||
@@ -170,3 +164,4 @@ distributed under the LGPL version 2.1 or later.
|
||||
Finally, special thanks goes to the original teams
|
||||
at Westwood Studios and EA for creating the classic
|
||||
games which OpenRA aims to reimagine.
|
||||
|
||||
|
||||
@@ -34,8 +34,10 @@ Type `sudo make install-all` for system wide installation. Run `make install-lin
|
||||
Debian/Ubuntu
|
||||
-------------
|
||||
|
||||
* mono-dmcs
|
||||
* libmono-system-windows-forms4.0-cil
|
||||
* nuget
|
||||
* mono-devel
|
||||
* cli-common-dev (>= 2.10)
|
||||
* libfreetype6
|
||||
* libopenal1
|
||||
* liblua5.1-0
|
||||
|
||||
136
Makefile
136
Makefile
@@ -6,11 +6,6 @@
|
||||
# to compile with development tools, run:
|
||||
# make all [DEBUG=false]
|
||||
#
|
||||
# to check unit tests (requires NUnit version >= 2.6), run:
|
||||
# make nunit [NUNIT_CONSOLE=<path-to/nunit[2]-console>] [NUNIT_LIBS_PATH=<path-to-libs-dir>] [NUNIT_LIBS=<nunit-libs>]
|
||||
# Use NUNIT_CONSOLE if nunit[3|2]-console was not downloaded by `make dependencies` nor is it in bin search paths
|
||||
# Use NUNIT_LIBS_PATH if NUnit libs are not in search paths. Include trailing /
|
||||
# Use NUNIT_LIBS if NUnit libs have different names (such as including a prefix or suffix)
|
||||
# to check the official mods for erroneous yaml files, run:
|
||||
# make test
|
||||
#
|
||||
@@ -42,13 +37,10 @@
|
||||
|
||||
############################## TOOLCHAIN ###############################
|
||||
#
|
||||
SDK ?=
|
||||
CSC = mcs $(SDK)
|
||||
CSC = dmcs
|
||||
CSFLAGS = -nologo -warn:4 -codepage:utf8 -unsafe -warnaserror
|
||||
DEFINE = TRACE
|
||||
COMMON_LIBS = System.dll System.Core.dll System.Data.dll System.Data.DataSetExtensions.dll System.Drawing.dll System.Xml.dll thirdparty/download/ICSharpCode.SharpZipLib.dll thirdparty/download/FuzzyLogicLibrary.dll thirdparty/download/Mono.Nat.dll thirdparty/download/MaxMind.Db.dll thirdparty/download/MaxMind.GeoIP2.dll thirdparty/download/Eluant.dll thirdparty/download/SmarIrc4net.dll
|
||||
NUNIT_LIBS_PATH :=
|
||||
NUNIT_LIBS := $(NUNIT_LIBS_PATH)nunit.framework.dll
|
||||
|
||||
DEBUG = true
|
||||
ifeq ($(DEBUG), $(filter $(DEBUG),false no n off 0))
|
||||
@@ -87,7 +79,7 @@ INSTALL_PROGRAM = $(INSTALL) -m755
|
||||
INSTALL_DATA = $(INSTALL) -m644
|
||||
|
||||
# program targets
|
||||
CORE = pdefault game utility server
|
||||
CORE = pdefault pnull game utility
|
||||
TOOLS = gamemonitor
|
||||
VERSION = $(shell git name-rev --name-only --tags --no-undefined HEAD 2>/dev/null || echo git-`git rev-parse --short HEAD`)
|
||||
|
||||
@@ -118,9 +110,15 @@ pdefault_SRCS := $(shell find OpenRA.Platforms.Default/ -iname '*.cs')
|
||||
pdefault_TARGET = OpenRA.Platforms.Default.dll
|
||||
pdefault_KIND = library
|
||||
pdefault_DEPS = $(game_TARGET)
|
||||
pdefault_LIBS = $(COMMON_LIBS) thirdparty/download/SDL2-CS.dll thirdparty/download/OpenAL-CS.dll $(pdefault_DEPS)
|
||||
PROGRAMS += pdefault
|
||||
platforms: $(pdefault_TARGET)
|
||||
pdefault_LIBS = $(COMMON_LIBS) thirdparty/download/SDL2-CS.dll $(pdefault_DEPS)
|
||||
|
||||
pnull_SRCS := $(shell find OpenRA.Platforms.Null/ -iname '*.cs')
|
||||
pnull_TARGET = OpenRA.Platforms.Null.dll
|
||||
pnull_KIND = library
|
||||
pnull_DEPS = $(game_TARGET)
|
||||
pnull_LIBS = $(COMMON_LIBS) $(pnull_DEPS)
|
||||
PROGRAMS += pdefault pnull
|
||||
platforms: $(pdefault_TARGET) $(pnull_TARGET)
|
||||
|
||||
# Mods Common
|
||||
mod_common_SRCS := $(shell find OpenRA.Mods.Common/ -iname '*.cs')
|
||||
@@ -131,16 +129,6 @@ mod_common_LIBS = $(COMMON_LIBS) $(STD_MOD_LIBS) thirdparty/download/StyleCop.dl
|
||||
PROGRAMS += mod_common
|
||||
mod_common: $(mod_common_TARGET)
|
||||
|
||||
# NUnit testing
|
||||
test_dll_SRCS := $(shell find OpenRA.Test/ -iname '*.cs')
|
||||
test_dll_TARGET = OpenRA.Test.dll
|
||||
test_dll_KIND = library
|
||||
test_dll_DEPS = $(game_TARGET) $(mod_common_TARGET)
|
||||
test_dll_FLAGS = -warn:1
|
||||
test_dll_LIBS = $(COMMON_LIBS) $(game_TARGET) $(mod_common_TARGET) $(NUNIT_LIBS)
|
||||
PROGRAMS += test_dll
|
||||
test_dll: $(test_dll_TARGET)
|
||||
|
||||
##### Official Mods #####
|
||||
|
||||
STD_MOD_LIBS = $(game_TARGET)
|
||||
@@ -196,6 +184,9 @@ check: utility mods
|
||||
@echo "Checking for code style violations in OpenRA.Platforms.Default..."
|
||||
@mono --debug OpenRA.Utility.exe ra --check-code-style OpenRA.Platforms.Default
|
||||
@echo
|
||||
@echo "Checking for code style violations in OpenRA.Platforms.Null..."
|
||||
@mono --debug OpenRA.Utility.exe ra --check-code-style OpenRA.Platforms.Null
|
||||
@echo
|
||||
@echo "Checking for code style violations in OpenRA.GameMonitor..."
|
||||
@mono --debug OpenRA.Utility.exe ra --check-code-style OpenRA.GameMonitor
|
||||
@echo
|
||||
@@ -219,31 +210,6 @@ check: utility mods
|
||||
@echo
|
||||
@echo "Checking for code style violations in OpenRA.Test..."
|
||||
@mono --debug OpenRA.Utility.exe ra --check-code-style OpenRA.Test
|
||||
@echo
|
||||
@echo "Checking for explicit interface violations..."
|
||||
@mono --debug OpenRA.Utility.exe all --check-explicit-interfaces
|
||||
@echo
|
||||
@echo "Checking for code style violations in OpenRA.Server..."
|
||||
@mono --debug OpenRA.Utility.exe ra --check-code-style OpenRA.Server
|
||||
|
||||
NUNIT_CONSOLE := $(shell test -f thirdparty/download/nunit3-console.exe && echo mono thirdparty/download/nunit3-console.exe || \
|
||||
which nunit3-console 2>/dev/null || which nunit2-console 2>/dev/null || which nunit-console 2>/dev/null)
|
||||
nunit: test_dll
|
||||
@echo
|
||||
@echo "Checking unit tests..."
|
||||
@if [ "$(NUNIT_CONSOLE)" = "" ] ; then \
|
||||
echo 'nunit[3|2]-console not found!'; \
|
||||
echo 'Was "make dependencies" called or is NUnit installed?'>&2; \
|
||||
echo 'See "make help".'; \
|
||||
exit 1; \
|
||||
fi
|
||||
@if $(NUNIT_CONSOLE) --help | head -n 1 | grep -E "NUnit version (1|2\.[0-5])";then \
|
||||
echo 'NUnit version >= 2.6 required'>&2; \
|
||||
echo 'Try "make dependencies" first to use NUnit from NuGet.'>&2; \
|
||||
echo 'See "make help".'; \
|
||||
exit 1; \
|
||||
fi
|
||||
@$(NUNIT_CONSOLE) --noresult OpenRA.Test.nunit
|
||||
|
||||
test: utility mods
|
||||
@echo
|
||||
@@ -280,15 +246,6 @@ utility_LIBS = $(COMMON_LIBS) $(utility_DEPS) thirdparty/download/ICSharpCode.Sh
|
||||
PROGRAMS += utility
|
||||
utility: $(utility_TARGET)
|
||||
|
||||
# Dedicated server
|
||||
server_SRCS := $(shell find OpenRA.Server/ -iname '*.cs')
|
||||
server_TARGET = OpenRA.Server.exe
|
||||
server_KIND = exe
|
||||
server_DEPS = $(game_TARGET)
|
||||
server_LIBS = $(COMMON_LIBS) $(server_DEPS)
|
||||
PROGRAMS += server
|
||||
server: $(server_TARGET)
|
||||
|
||||
# Patches binary headers to work around a mono bug
|
||||
fixheader.exe: packaging/fixheader.cs
|
||||
@echo CSC fixheader.exe
|
||||
@@ -318,7 +275,7 @@ $(foreach prog,$(PROGRAMS),$(eval $(call BUILD_ASSEMBLY,$(prog))))
|
||||
#
|
||||
default: core
|
||||
|
||||
core: game platforms mods utility server
|
||||
core: game platforms mods utility
|
||||
|
||||
tools: gamemonitor
|
||||
|
||||
@@ -339,6 +296,7 @@ cli-dependencies:
|
||||
@./thirdparty/fetch-thirdparty-deps.sh
|
||||
@ $(CP_R) thirdparty/download/*.dll .
|
||||
@ $(CP_R) thirdparty/download/*.dll.config .
|
||||
@ $(CP) thirdparty/SDL2-CS.dll.config .
|
||||
|
||||
linux-dependencies: cli-dependencies linux-native-dependencies
|
||||
|
||||
@@ -362,9 +320,7 @@ all-dependencies: cli-dependencies windows-dependencies osx-dependencies
|
||||
version: mods/ra/mod.yaml mods/cnc/mod.yaml mods/d2k/mod.yaml mods/ts/mod.yaml mods/modchooser/mod.yaml mods/all/mod.yaml
|
||||
@for i in $? ; do \
|
||||
awk '{sub("Version:.*$$","Version: $(VERSION)"); print $0}' $${i} > $${i}.tmp && \
|
||||
awk '{sub("\tmodchooser:.*$$","\tmodchooser: $(VERSION)"); print $0}' $${i}.tmp > $${i}.tmp2 && \
|
||||
awk '{sub("/[^/]*: User$$", "/$(VERSION): User"); print $0}' $${i}.tmp2 > $${i} && \
|
||||
rm $${i}.tmp $${i}.tmp2; \
|
||||
mv -f $${i}.tmp $${i} ; \
|
||||
done
|
||||
|
||||
docs: utility mods version
|
||||
@@ -403,7 +359,6 @@ install-core: default
|
||||
@$(CP_R) glsl "$(DATA_INSTALL_DIR)"
|
||||
@$(CP_R) lua "$(DATA_INSTALL_DIR)"
|
||||
@$(CP) SDL2-CS* "$(DATA_INSTALL_DIR)"
|
||||
@$(CP) OpenAL-CS* "$(DATA_INSTALL_DIR)"
|
||||
@$(CP) Eluant* "$(DATA_INSTALL_DIR)"
|
||||
@$(INSTALL_PROGRAM) ICSharpCode.SharpZipLib.dll "$(DATA_INSTALL_DIR)"
|
||||
@$(INSTALL_PROGRAM) FuzzyLogicLibrary.dll "$(DATA_INSTALL_DIR)"
|
||||
@@ -468,22 +423,9 @@ endif
|
||||
@$(INSTALL_PROGRAM) -m +rx openra "$(BIN_INSTALL_DIR)"
|
||||
@-$(RM) openra
|
||||
|
||||
@echo "#!/bin/sh" > openra-server
|
||||
@echo 'cd "$(gameinstalldir)"' >> openra-server
|
||||
ifeq ($(DEBUG), $(filter $(DEBUG),false no n off 0))
|
||||
@echo 'mono OpenRA.Server.exe "$$@"' >> openra-server
|
||||
else
|
||||
@echo 'mono --debug OpenRA.Server.exe "$$@"' >> openra-server
|
||||
endif
|
||||
|
||||
@$(INSTALL_DIR) "$(BIN_INSTALL_DIR)"
|
||||
@$(INSTALL_PROGRAM) -m +rx openra-server "$(BIN_INSTALL_DIR)"
|
||||
@-$(RM) openra-server
|
||||
|
||||
uninstall:
|
||||
@-$(RM_R) "$(DATA_INSTALL_DIR)"
|
||||
@-$(RM_F) "$(BIN_INSTALL_DIR)/openra"
|
||||
@-$(RM_F) "$(BIN_INSTALL_DIR)/openra-server"
|
||||
@-$(RM_F) "$(DESTDIR)$(datadir)/applications/openra.desktop"
|
||||
@-$(RM_F) "$(DESTDIR)$(datadir)/icons/hicolor/16x16/apps/openra.png"
|
||||
@-$(RM_F) "$(DESTDIR)$(datadir)/icons/hicolor/32x32/apps/openra.png"
|
||||
@@ -495,38 +437,32 @@ uninstall:
|
||||
@-$(RM_F) "$(DESTDIR)$(mandir)/man6/openra.6"
|
||||
|
||||
help:
|
||||
@echo 'to compile, run:'
|
||||
@echo ' make [DEBUG=false]'
|
||||
@echo to compile, run:
|
||||
@echo \ \ make [DEBUG=false]
|
||||
@echo
|
||||
@echo 'to compile with development tools, run:'
|
||||
@echo ' make all [DEBUG=false]'
|
||||
@echo to compile with development tools, run:
|
||||
@echo \ \ make all [DEBUG=false]
|
||||
@echo
|
||||
@echo 'to check unit tests (requires NUnit version >= 2.6), run:'
|
||||
@echo ' make nunit [NUNIT_CONSOLE=<path-to/nunit[3|2]-console>] [NUNIT_LIBS_PATH=<path-to-libs-dir>] [NUNIT_LIBS=<nunit-libs>]'
|
||||
@echo ' Use NUNIT_CONSOLE if nunit[3|2]-console was not downloaded by `make dependencies` nor is it in bin search paths'
|
||||
@echo ' Use NUNIT_LIBS_PATH if NUnit libs are not in search paths. Include trailing /'
|
||||
@echo ' Use NUNIT_LIBS if NUnit libs have different names (such as including a prefix or suffix)'
|
||||
@echo to check the official mods for erroneous yaml files, run:
|
||||
@echo \ \ make test
|
||||
@echo
|
||||
@echo 'to check the official mods for erroneous yaml files, run:'
|
||||
@echo ' make test'
|
||||
@echo to generate documentation aimed at modders, run:
|
||||
@echo \ \ make docs
|
||||
@echo
|
||||
@echo 'to generate documentation aimed at modders, run:'
|
||||
@echo ' make docs'
|
||||
@echo to install, run:
|
||||
@echo \ \ make \[prefix=/foo\] \[bindir=/bar/bin\] install
|
||||
@echo
|
||||
@echo 'to install, run:'
|
||||
@echo ' make [prefix=/foo] [bindir=/bar/bin] install'
|
||||
@echo to install with development tools, run:
|
||||
@echo \ \ make \[prefix=/foo\] \[bindir=/bar/bin\] install-all
|
||||
@echo
|
||||
@echo 'to install with development tools, run:'
|
||||
@echo ' make [prefix=/foo] [bindir=/bar/bin] install-all'
|
||||
@echo to install Linux startup scripts, desktop files and icons
|
||||
@echo \ \ make install-linux-shortcuts [DEBUG=false]
|
||||
@echo
|
||||
@echo 'to install Linux startup scripts, desktop files and icons'
|
||||
@echo ' make install-linux-shortcuts [DEBUG=false]'
|
||||
@echo to uninstall, run:
|
||||
@echo \ \ make uninstall
|
||||
@echo
|
||||
@echo 'to uninstall, run:'
|
||||
@echo ' make uninstall'
|
||||
@echo
|
||||
@echo 'to start the game, run:'
|
||||
@echo ' openra'
|
||||
@echo to start the game, run:
|
||||
@echo \ \ openra
|
||||
|
||||
|
||||
|
||||
@@ -537,4 +473,4 @@ help:
|
||||
|
||||
.SUFFIXES:
|
||||
|
||||
.PHONY: core tools package all mods clean distclean dependencies version $(PROGRAMS) nunit
|
||||
.PHONY: core tools package all mods clean distclean dependencies version $(PROGRAMS)
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
@@ -25,13 +24,6 @@ namespace OpenRA
|
||||
{
|
||||
public sealed class Actor : IScriptBindable, IScriptNotifyBind, ILuaTableBinding, ILuaEqualityBinding, ILuaToStringBinding, IEquatable<Actor>, IDisposable
|
||||
{
|
||||
internal struct SyncHash
|
||||
{
|
||||
public readonly ISync Trait;
|
||||
public readonly int Hash;
|
||||
public SyncHash(ISync trait, int hash) { Trait = trait; Hash = hash; }
|
||||
}
|
||||
|
||||
public readonly ActorInfo Info;
|
||||
|
||||
public readonly World World;
|
||||
@@ -52,7 +44,6 @@ namespace OpenRA
|
||||
public Rectangle VisualBounds { get; private set; }
|
||||
public IEffectiveOwner EffectiveOwner { get; private set; }
|
||||
public IOccupySpace OccupiesSpace { get; private set; }
|
||||
public ITargetable[] Targetables { get; private set; }
|
||||
|
||||
public bool IsIdle { get { return currentActivity == null; } }
|
||||
public bool IsDead { get { return Disposed || (health != null && health.IsDead); } }
|
||||
@@ -70,8 +61,6 @@ namespace OpenRA
|
||||
}
|
||||
}
|
||||
|
||||
internal IEnumerable<SyncHash> SyncHashes { get; private set; }
|
||||
|
||||
readonly IFacing facing;
|
||||
readonly IHealth health;
|
||||
readonly IRenderModifier[] renderModifiers;
|
||||
@@ -108,9 +97,6 @@ namespace OpenRA
|
||||
}
|
||||
}
|
||||
|
||||
// PERF: Cache all these traits as soon as the actor is created. This is a fairly cheap one-off cost per
|
||||
// actor that allows us to provide some fast implementations of commonly used methods that are relied on by
|
||||
// performance-sensitive parts of the core game engine, such as pathfinding, visibility and rendering.
|
||||
Bounds = DetermineBounds();
|
||||
VisualBounds = DetermineVisualBounds();
|
||||
EffectiveOwner = TraitOrDefault<IEffectiveOwner>();
|
||||
@@ -121,13 +107,6 @@ namespace OpenRA
|
||||
disables = TraitsImplementing<IDisable>().ToArray();
|
||||
visibilityModifiers = TraitsImplementing<IVisibilityModifier>().ToArray();
|
||||
defaultVisibility = Trait<IDefaultVisibility>();
|
||||
Targetables = TraitsImplementing<ITargetable>().ToArray();
|
||||
|
||||
SyncHashes =
|
||||
TraitsImplementing<ISync>()
|
||||
.Select(sync => Pair.New(sync, Sync.GetHashFunction(sync)))
|
||||
.ToArray()
|
||||
.Select(pair => new SyncHash(pair.First, pair.Second(pair.First)));
|
||||
}
|
||||
|
||||
Rectangle DetermineBounds()
|
||||
@@ -161,7 +140,7 @@ namespace OpenRA
|
||||
public void Tick()
|
||||
{
|
||||
var wasIdle = IsIdle;
|
||||
currentActivity = ActivityUtils.RunActivity(this, currentActivity);
|
||||
currentActivity = Traits.Util.RunActivity(this, currentActivity);
|
||||
|
||||
if (!wasIdle && IsIdle)
|
||||
foreach (var n in TraitsImplementing<INotifyBecomingIdle>())
|
||||
@@ -170,7 +149,6 @@ namespace OpenRA
|
||||
|
||||
public IEnumerable<IRenderable> Render(WorldRenderer wr)
|
||||
{
|
||||
// PERF: Avoid LINQ.
|
||||
var renderables = Renderables(wr);
|
||||
foreach (var modifier in renderModifiers)
|
||||
renderables = modifier.ModifyRender(this, wr, renderables);
|
||||
@@ -179,13 +157,6 @@ namespace OpenRA
|
||||
|
||||
IEnumerable<IRenderable> Renderables(WorldRenderer wr)
|
||||
{
|
||||
// PERF: Avoid LINQ.
|
||||
// Implementations of Render are permitted to return both an eagerly materialized collection or a lazily
|
||||
// generated sequence.
|
||||
// For large amounts of renderables, a lazily generated sequence (e.g. as returned by LINQ, or by using
|
||||
// `yield`) will avoid the need to allocate a large collection.
|
||||
// For small amounts of renderables, allocating a small collection can often be faster and require less
|
||||
// memory than creating the objects needed to represent a sequence.
|
||||
foreach (var render in renders)
|
||||
foreach (var renderable in render.Render(this, wr))
|
||||
yield return renderable;
|
||||
@@ -235,7 +206,6 @@ namespace OpenRA
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
// PERF: Avoid format strings.
|
||||
var name = Info.Name + " " + ActorID;
|
||||
if (!IsInWorld)
|
||||
name += " (not in world)";
|
||||
@@ -304,7 +274,7 @@ namespace OpenRA
|
||||
if (wasInWorld)
|
||||
w.Add(this);
|
||||
|
||||
foreach (var t in TraitsImplementing<INotifyOwnerChanged>())
|
||||
foreach (var t in this.TraitsImplementing<INotifyOwnerChanged>())
|
||||
t.OnOwnerChanged(this, oldOwner, newOwner);
|
||||
});
|
||||
}
|
||||
@@ -335,7 +305,6 @@ namespace OpenRA
|
||||
|
||||
public bool IsDisabled()
|
||||
{
|
||||
// PERF: Avoid LINQ.
|
||||
foreach (var disable in disables)
|
||||
if (disable.Disabled)
|
||||
return true;
|
||||
@@ -344,7 +313,6 @@ namespace OpenRA
|
||||
|
||||
public bool CanBeViewedByPlayer(Player player)
|
||||
{
|
||||
// PERF: Avoid LINQ.
|
||||
foreach (var visibilityModifier in visibilityModifiers)
|
||||
if (!visibilityModifier.IsVisible(this, player))
|
||||
return false;
|
||||
@@ -352,33 +320,6 @@ namespace OpenRA
|
||||
return defaultVisibility.IsVisible(this, player);
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetAllTargetTypes()
|
||||
{
|
||||
// PERF: Avoid LINQ.
|
||||
foreach (var targetable in Targetables)
|
||||
foreach (var targetType in targetable.TargetTypes)
|
||||
yield return targetType;
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetEnabledTargetTypes()
|
||||
{
|
||||
// PERF: Avoid LINQ.
|
||||
foreach (var targetable in Targetables)
|
||||
if (targetable.IsTraitEnabled())
|
||||
foreach (var targetType in targetable.TargetTypes)
|
||||
yield return targetType;
|
||||
}
|
||||
|
||||
public bool IsTargetableBy(Actor byActor)
|
||||
{
|
||||
// PERF: Avoid LINQ.
|
||||
foreach (var targetable in Targetables)
|
||||
if (targetable.IsTraitEnabled() && targetable.TargetableBy(this, byActor))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#region Scripting interface
|
||||
|
||||
Lazy<ScriptActorInterface> luaInterface;
|
||||
@@ -397,7 +338,7 @@ namespace OpenRA
|
||||
public LuaValue Equals(LuaRuntime runtime, LuaValue left, LuaValue right)
|
||||
{
|
||||
Actor a, b;
|
||||
if (!left.TryGetClrValue(out a) || !right.TryGetClrValue(out b))
|
||||
if (!left.TryGetClrValue<Actor>(out a) || !right.TryGetClrValue<Actor>(out b))
|
||||
return false;
|
||||
|
||||
return a == b;
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
@@ -74,7 +73,7 @@ namespace OpenRA
|
||||
{
|
||||
CPos a;
|
||||
CVec b;
|
||||
if (!left.TryGetClrValue(out a) || !right.TryGetClrValue(out b))
|
||||
if (!left.TryGetClrValue<CPos>(out a) || !right.TryGetClrValue<CVec>(out b))
|
||||
throw new LuaException("Attempted to call CPos.Add(CPos, CVec) with invalid arguments ({0}, {1})".F(left.WrappedClrType().Name, right.WrappedClrType().Name));
|
||||
|
||||
return new LuaCustomClrObject(a + b);
|
||||
@@ -84,7 +83,7 @@ namespace OpenRA
|
||||
{
|
||||
CPos a;
|
||||
CVec b;
|
||||
if (!left.TryGetClrValue(out a) || !right.TryGetClrValue(out b))
|
||||
if (!left.TryGetClrValue<CPos>(out a) || !right.TryGetClrValue<CVec>(out b))
|
||||
throw new LuaException("Attempted to call CPos.Subtract(CPos, CVec) with invalid arguments ({0}, {1})".F(left.WrappedClrType().Name, right.WrappedClrType().Name));
|
||||
|
||||
return new LuaCustomClrObject(a - b);
|
||||
@@ -93,7 +92,7 @@ namespace OpenRA
|
||||
public LuaValue Equals(LuaRuntime runtime, LuaValue left, LuaValue right)
|
||||
{
|
||||
CPos a, b;
|
||||
if (!left.TryGetClrValue(out a) || !right.TryGetClrValue(out b))
|
||||
if (!left.TryGetClrValue<CPos>(out a) || !right.TryGetClrValue<CPos>(out b))
|
||||
return false;
|
||||
|
||||
return a == b;
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
@@ -76,7 +75,7 @@ namespace OpenRA
|
||||
public LuaValue Add(LuaRuntime runtime, LuaValue left, LuaValue right)
|
||||
{
|
||||
CVec a, b;
|
||||
if (!left.TryGetClrValue(out a) || !right.TryGetClrValue(out b))
|
||||
if (!left.TryGetClrValue<CVec>(out a) || !right.TryGetClrValue<CVec>(out b))
|
||||
throw new LuaException("Attempted to call CVec.Add(CVec, CVec) with invalid arguments ({0}, {1})".F(left.WrappedClrType().Name, right.WrappedClrType().Name));
|
||||
|
||||
return new LuaCustomClrObject(a + b);
|
||||
@@ -85,7 +84,7 @@ namespace OpenRA
|
||||
public LuaValue Subtract(LuaRuntime runtime, LuaValue left, LuaValue right)
|
||||
{
|
||||
CVec a, b;
|
||||
if (!left.TryGetClrValue(out a) || !right.TryGetClrValue(out b))
|
||||
if (!left.TryGetClrValue<CVec>(out a) || !right.TryGetClrValue<CVec>(out b))
|
||||
throw new LuaException("Attempted to call CVec.Subtract(CVec, CVec) with invalid arguments ({0}, {1})".F(left.WrappedClrType().Name, right.WrappedClrType().Name));
|
||||
|
||||
return new LuaCustomClrObject(a - b);
|
||||
@@ -99,7 +98,7 @@ namespace OpenRA
|
||||
public LuaValue Equals(LuaRuntime runtime, LuaValue left, LuaValue right)
|
||||
{
|
||||
CVec a, b;
|
||||
if (!left.TryGetClrValue(out a) || !right.TryGetClrValue(out b))
|
||||
if (!left.TryGetClrValue<CVec>(out a) || !right.TryGetClrValue<CVec>(out b))
|
||||
return false;
|
||||
|
||||
return a == b;
|
||||
@@ -119,7 +118,7 @@ namespace OpenRA
|
||||
|
||||
set
|
||||
{
|
||||
throw new LuaException("CVec is read-only. Use CVec.New to create a new value");
|
||||
throw new LuaException("WVec is read-only. Use CVec.New to create a new value");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
@@ -16,14 +15,11 @@ namespace OpenRA
|
||||
// Referenced from ModMetadata, so needs to be in OpenRA.Game :(
|
||||
public class ContentInstaller : IGlobalModData
|
||||
{
|
||||
public enum FilenameCase { Input, ForceLower, ForceUpper }
|
||||
|
||||
public readonly string[] TestFiles = { };
|
||||
public readonly string[] DiskTestFiles = { };
|
||||
public readonly string PackageToExtractFromCD = null;
|
||||
public readonly bool OverwriteFiles = true;
|
||||
|
||||
public readonly FilenameCase OutputFilenameCase = FilenameCase.ForceLower;
|
||||
public readonly Dictionary<string, string[]> CopyFilesFromCD = new Dictionary<string, string[]>();
|
||||
public readonly Dictionary<string, string[]> ExtractFilesFromCD = new Dictionary<string, string[]>();
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
@@ -16,22 +15,16 @@ namespace OpenRA.Effects
|
||||
{
|
||||
public class SpriteEffect : IEffect
|
||||
{
|
||||
readonly World world;
|
||||
readonly string palette;
|
||||
readonly Animation anim;
|
||||
readonly WPos pos;
|
||||
readonly bool visibleThroughFog;
|
||||
readonly bool scaleSizeWithZoom;
|
||||
|
||||
public SpriteEffect(WPos pos, World world, string image, string sequence, string palette, bool visibleThroughFog = false, bool scaleSizeWithZoom = false)
|
||||
public SpriteEffect(WPos pos, World world, string image, string palette)
|
||||
{
|
||||
this.world = world;
|
||||
this.pos = pos;
|
||||
this.palette = palette;
|
||||
this.scaleSizeWithZoom = scaleSizeWithZoom;
|
||||
this.visibleThroughFog = visibleThroughFog;
|
||||
anim = new Animation(world, image);
|
||||
anim.PlayThen(sequence, () => world.AddFrameEndTask(w => w.Remove(this)));
|
||||
anim.PlayThen("idle", () => world.AddFrameEndTask(w => w.Remove(this)));
|
||||
}
|
||||
|
||||
public void Tick(World world)
|
||||
@@ -41,11 +34,7 @@ namespace OpenRA.Effects
|
||||
|
||||
public IEnumerable<IRenderable> Render(WorldRenderer wr)
|
||||
{
|
||||
if (world.FogObscures(pos) && !visibleThroughFog)
|
||||
return SpriteRenderable.None;
|
||||
|
||||
var zoom = scaleSizeWithZoom ? 1f / wr.Viewport.Zoom : 1f;
|
||||
return anim.Render(pos, WVec.Zero, 0, wr.Palette(palette), zoom);
|
||||
return anim.Render(pos, WVec.Zero, 0, wr.Palette(palette), 1f / wr.Viewport.Zoom);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
@@ -114,7 +113,6 @@ namespace OpenRA
|
||||
|
||||
public static bool HasModifier(this Modifiers k, Modifiers mod)
|
||||
{
|
||||
// PERF: Enum.HasFlag is slower and requires allocations.
|
||||
return (k & mod) == mod;
|
||||
}
|
||||
|
||||
@@ -328,15 +326,6 @@ namespace OpenRA
|
||||
return root;
|
||||
}
|
||||
|
||||
public static int IntegerDivisionRoundingAwayFromZero(int dividend, int divisor)
|
||||
{
|
||||
int remainder;
|
||||
var quotient = Math.DivRem(dividend, divisor, out remainder);
|
||||
if (remainder == 0)
|
||||
return quotient;
|
||||
return quotient + (Math.Sign(dividend) == Math.Sign(divisor) ? 1 : -1);
|
||||
}
|
||||
|
||||
public static string JoinWith<T>(this IEnumerable<T> ts, string j)
|
||||
{
|
||||
return string.Join(j, ts);
|
||||
@@ -361,7 +350,7 @@ namespace OpenRA
|
||||
|
||||
public static Dictionary<TKey, TElement> ToDictionaryWithConflictLog<TSource, TKey, TElement>(
|
||||
this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector,
|
||||
string debugName, Func<TKey, string> logKey = null, Func<TElement, string> logValue = null)
|
||||
string debugName, Func<TKey, string> logKey, Func<TElement, string> logValue)
|
||||
{
|
||||
// Fall back on ToString() if null functions are provided:
|
||||
logKey = logKey ?? (s => s.ToString());
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
@@ -17,7 +16,6 @@ using System.Drawing.Imaging;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text.RegularExpressions;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Primitives;
|
||||
@@ -26,7 +24,6 @@ namespace OpenRA
|
||||
{
|
||||
public static class FieldLoader
|
||||
{
|
||||
[Serializable]
|
||||
public class MissingFieldsException : YamlException
|
||||
{
|
||||
public readonly string[] Missing;
|
||||
@@ -45,13 +42,6 @@ namespace OpenRA
|
||||
Header = missing.Length > 1 ? header : headerSingle ?? header;
|
||||
Missing = missing;
|
||||
}
|
||||
|
||||
public override void GetObjectData(SerializationInfo info, StreamingContext context)
|
||||
{
|
||||
base.GetObjectData(info, context);
|
||||
info.AddValue("Missing", Missing);
|
||||
info.AddValue("Header", Header);
|
||||
}
|
||||
}
|
||||
|
||||
public static Func<string, Type, string, object> InvalidValueAction = (s, t, f) =>
|
||||
@@ -222,9 +212,21 @@ namespace OpenRA
|
||||
}
|
||||
else if (fieldType == typeof(Color))
|
||||
{
|
||||
Color color;
|
||||
if (value != null && HSLColor.TryParseRGB(value, out color))
|
||||
return color;
|
||||
if (value != null)
|
||||
{
|
||||
var parts = value.Split(',');
|
||||
if (parts.Length == 3)
|
||||
return Color.FromArgb(
|
||||
Exts.ParseIntegerInvariant(parts[0]).Clamp(0, 255),
|
||||
Exts.ParseIntegerInvariant(parts[1]).Clamp(0, 255),
|
||||
Exts.ParseIntegerInvariant(parts[2]).Clamp(0, 255));
|
||||
if (parts.Length == 4)
|
||||
return Color.FromArgb(
|
||||
Exts.ParseIntegerInvariant(parts[0]).Clamp(0, 255),
|
||||
Exts.ParseIntegerInvariant(parts[1]).Clamp(0, 255),
|
||||
Exts.ParseIntegerInvariant(parts[2]).Clamp(0, 255),
|
||||
Exts.ParseIntegerInvariant(parts[3]).Clamp(0, 255));
|
||||
}
|
||||
|
||||
return InvalidValueAction(value, fieldType, fieldName);
|
||||
}
|
||||
@@ -233,11 +235,20 @@ namespace OpenRA
|
||||
if (value != null)
|
||||
{
|
||||
var parts = value.Split(',');
|
||||
var colors = new Color[parts.Length];
|
||||
|
||||
if (parts.Length % 4 != 0)
|
||||
return InvalidValueAction(value, fieldType, fieldName);
|
||||
|
||||
var colors = new Color[parts.Length / 4];
|
||||
|
||||
for (var i = 0; i < colors.Length; i++)
|
||||
if (!HSLColor.TryParseRGB(parts[i], out colors[i]))
|
||||
return InvalidValueAction(value, fieldType, fieldName);
|
||||
{
|
||||
colors[i] = Color.FromArgb(
|
||||
Exts.ParseIntegerInvariant(parts[4 * i]).Clamp(0, 255),
|
||||
Exts.ParseIntegerInvariant(parts[4 * i + 1]).Clamp(0, 255),
|
||||
Exts.ParseIntegerInvariant(parts[4 * i + 2]).Clamp(0, 255),
|
||||
Exts.ParseIntegerInvariant(parts[4 * i + 3]).Clamp(0, 255));
|
||||
}
|
||||
|
||||
return colors;
|
||||
}
|
||||
@@ -248,12 +259,9 @@ namespace OpenRA
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
Color rgb;
|
||||
if (HSLColor.TryParseRGB(value, out rgb))
|
||||
return new HSLColor(rgb);
|
||||
|
||||
// Allow old HSLColor/ColorRamp formats to be parsed as HSLColor
|
||||
var parts = value.Split(',');
|
||||
|
||||
// Allow old ColorRamp format to be parsed as HSLColor
|
||||
if (parts.Length == 3 || parts.Length == 4)
|
||||
return new HSLColor(
|
||||
(byte)Exts.ParseIntegerInvariant(parts[0]).Clamp(0, 255),
|
||||
@@ -374,28 +382,6 @@ namespace OpenRA
|
||||
|
||||
return InvalidValueAction(value, fieldType, fieldName);
|
||||
}
|
||||
else if (fieldType == typeof(CVec[]))
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
var parts = value.Split(',');
|
||||
|
||||
if (parts.Length % 2 != 0)
|
||||
return InvalidValueAction(value, fieldType, fieldName);
|
||||
|
||||
var vecs = new CVec[parts.Length / 2];
|
||||
for (var i = 0; i < vecs.Length; i++)
|
||||
{
|
||||
int rx, ry;
|
||||
if (int.TryParse(parts[2 * i], out rx) && int.TryParse(parts[2 * i + 1], out ry))
|
||||
vecs[i] = new CVec(rx, ry);
|
||||
}
|
||||
|
||||
return vecs;
|
||||
}
|
||||
|
||||
return InvalidValueAction(value, fieldType, fieldName);
|
||||
}
|
||||
else if (fieldType.IsEnum)
|
||||
{
|
||||
try
|
||||
@@ -736,7 +722,7 @@ namespace OpenRA
|
||||
}
|
||||
}
|
||||
|
||||
// Mirrors DescriptionAttribute from System.ComponentModel but we don't want to have to use that everywhere.
|
||||
// mirrors DescriptionAttribute from System.ComponentModel but we dont want to have to use that everywhere.
|
||||
[AttributeUsage(AttributeTargets.All)]
|
||||
public sealed class DescAttribute : Attribute
|
||||
{
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
@@ -17,7 +16,6 @@ using System.Drawing.Imaging;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using OpenRA.Graphics;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
@@ -75,16 +73,14 @@ namespace OpenRA
|
||||
|
||||
var t = v.GetType();
|
||||
|
||||
// Color.ToString() does the wrong thing; force it to format as rgb[a] hex
|
||||
// Color.ToString() does the wrong thing; force it to format as an array
|
||||
if (t == typeof(Color))
|
||||
{
|
||||
return HSLColor.ToHexString((Color)v);
|
||||
}
|
||||
|
||||
// HSLColor.ToString() does the wrong thing; force it to format as rgb[a] hex
|
||||
if (t == typeof(HSLColor))
|
||||
{
|
||||
return ((HSLColor)v).ToHexString();
|
||||
var c = (Color)v;
|
||||
return "{0},{1},{2},{3}".F(((int)c.A).Clamp(0, 255),
|
||||
((int)c.R).Clamp(0, 255),
|
||||
((int)c.G).Clamp(0, 255),
|
||||
((int)c.B).Clamp(0, 255));
|
||||
}
|
||||
|
||||
if (t == typeof(ImageFormat))
|
||||
@@ -127,7 +123,7 @@ namespace OpenRA
|
||||
return result;
|
||||
}
|
||||
|
||||
if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Primitives.Cache<,>))
|
||||
if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(OpenRA.Primitives.Cache<,>))
|
||||
return ""; // TODO
|
||||
|
||||
if (t == typeof(DateTime))
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
@@ -37,88 +36,16 @@ namespace OpenRA.FileFormats
|
||||
Chunk c;
|
||||
c.CompressedSize = s.ReadUInt16();
|
||||
c.OutputSize = s.ReadUInt16();
|
||||
|
||||
if (s.ReadUInt32() != 0xdeaf)
|
||||
throw new InvalidDataException("Chunk header is bogus");
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
public class AudLoader : ISoundLoader
|
||||
public static class AudLoader
|
||||
{
|
||||
bool IsAud(Stream s)
|
||||
{
|
||||
var start = s.Position;
|
||||
s.Position += 10;
|
||||
var readFlag = s.ReadByte();
|
||||
var readFormat = s.ReadByte();
|
||||
s.Position = start;
|
||||
|
||||
if (!Enum.IsDefined(typeof(SoundFlags), readFlag))
|
||||
return false;
|
||||
|
||||
return Enum.IsDefined(typeof(SoundFormat), readFormat);
|
||||
}
|
||||
|
||||
bool ISoundLoader.TryParseSound(Stream stream, out ISoundFormat sound)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (IsAud(stream))
|
||||
{
|
||||
sound = new AudFormat(stream);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Not a supported AUD
|
||||
}
|
||||
|
||||
sound = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public class AudFormat : ISoundFormat
|
||||
{
|
||||
public int Channels { get { return 1; } }
|
||||
public int SampleBits { get { return 16; } }
|
||||
public int SampleRate { get { return sampleRate; } }
|
||||
public float LengthInSeconds { get { return AudReader.SoundLength(stream); } }
|
||||
public Stream GetPCMInputStream() { return new MemoryStream(rawData.Value); }
|
||||
|
||||
int sampleRate;
|
||||
Lazy<byte[]> rawData;
|
||||
|
||||
Stream stream;
|
||||
|
||||
public AudFormat(Stream stream)
|
||||
{
|
||||
this.stream = stream;
|
||||
|
||||
var position = stream.Position;
|
||||
rawData = Exts.Lazy(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] data;
|
||||
if (!AudReader.LoadSound(stream, out data, out sampleRate))
|
||||
throw new InvalidDataException();
|
||||
return data;
|
||||
}
|
||||
finally
|
||||
{
|
||||
stream.Position = position;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class AudReader
|
||||
{
|
||||
static readonly int[] IndexAdjust = { -1, -1, -1, -1, 2, 4, 6, 8 };
|
||||
static readonly int[] StepTable =
|
||||
static int[] indexAdjust = { -1, -1, -1, -1, 2, 4, 6, 8 };
|
||||
static int[] stepTable =
|
||||
{
|
||||
7, 8, 9, 10, 11, 12, 13, 14, 16,
|
||||
17, 19, 21, 23, 25, 28, 31, 34, 37,
|
||||
@@ -137,14 +64,14 @@ namespace OpenRA.FileFormats
|
||||
var sb = (b & 8) != 0;
|
||||
b &= 7;
|
||||
|
||||
var delta = (StepTable[index] * b) / 4 + StepTable[index] / 8;
|
||||
var delta = (stepTable[index] * b) / 4 + stepTable[index] / 8;
|
||||
if (sb) delta = -delta;
|
||||
|
||||
current += delta;
|
||||
if (current > short.MaxValue) current = short.MaxValue;
|
||||
if (current < short.MinValue) current = short.MinValue;
|
||||
|
||||
index += IndexAdjust[b];
|
||||
index += indexAdjust[b];
|
||||
if (index < 0) index = 0;
|
||||
if (index > 88) index = 88;
|
||||
|
||||
@@ -190,21 +117,13 @@ namespace OpenRA.FileFormats
|
||||
return samples / sampleRate;
|
||||
}
|
||||
|
||||
public static bool LoadSound(Stream s, out byte[] rawData, out int sampleRate)
|
||||
public static byte[] LoadSound(Stream s)
|
||||
{
|
||||
rawData = null;
|
||||
|
||||
sampleRate = s.ReadUInt16();
|
||||
/*var sampleRate =*/ s.ReadUInt16();
|
||||
var dataSize = s.ReadInt32();
|
||||
var outputSize = s.ReadInt32();
|
||||
|
||||
var readFlag = s.ReadByte();
|
||||
if (!Enum.IsDefined(typeof(SoundFlags), readFlag))
|
||||
return false;
|
||||
|
||||
var readFormat = s.ReadByte();
|
||||
if (!Enum.IsDefined(typeof(SoundFormat), readFormat))
|
||||
return false;
|
||||
/*var flags = (SoundFlags)*/ s.ReadByte();
|
||||
/*var format = (SoundFormat)*/ s.ReadByte();
|
||||
|
||||
var output = new byte[outputSize];
|
||||
var offset = 0;
|
||||
@@ -234,8 +153,7 @@ namespace OpenRA.FileFormats
|
||||
dataSize -= 8 + chunk.CompressedSize;
|
||||
}
|
||||
|
||||
rawData = output;
|
||||
return true;
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*
|
||||
* This file is based on the blast routines (version 1.1 by Mark Adler)
|
||||
* included in zlib/contrib
|
||||
@@ -66,7 +65,7 @@ namespace OpenRA.FileFormats
|
||||
var coded = br.ReadBits(8);
|
||||
|
||||
if (coded < 0 || coded > 1)
|
||||
throw new NotImplementedException("Invalid data stream");
|
||||
throw new NotImplementedException("Invalid datastream");
|
||||
var encodedLiterals = coded == 1;
|
||||
|
||||
// log2(dictionary size) - 6
|
||||
@@ -161,7 +160,7 @@ namespace OpenRA.FileFormats
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
// Decode a code using Huffman table h.
|
||||
// Decode a code using huffman table h.
|
||||
static int Decode(Huffman h, BitReader br)
|
||||
{
|
||||
var code = 0; // len bits being decoded
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
@@ -56,7 +55,7 @@ namespace OpenRA.FileFormats
|
||||
{
|
||||
var pn = (byte*)tempPn;
|
||||
var i = blen * 4;
|
||||
for (; i > klen; i--) pn[i - 1] = sign;
|
||||
for (; i > klen; i--) pn[i - 1] = (byte)sign;
|
||||
for (; i > 0; i--) pn[i - 1] = key[klen - i];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
@@ -112,11 +111,11 @@ namespace OpenRA.FileFormats
|
||||
|
||||
/// <summary>
|
||||
/// A fast (native) CRC32 implementation that can be used on a pinned byte array using
|
||||
/// default polynomial.
|
||||
/// default polynomal.
|
||||
/// </summary>
|
||||
/// <param name="data"> [in,out] If non-null, the.</param>
|
||||
/// <param name="len"> The length of the data.</param>
|
||||
/// <param name="polynomial">The polynomial to XOR with.</param>
|
||||
/// <param name="len"> The length of the data data.</param>
|
||||
/// <param name="polynomial">The polynomal to xor with.</param>
|
||||
/// <returns>The calculated checksum.</returns>
|
||||
public static unsafe uint Calculate(byte* data, uint len, uint polynomial)
|
||||
{
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
namespace OpenRA.Mods.Common.FileFormats
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
// Run length encoded sequences of zeros (aka Format2)
|
||||
public static class RLEZerosCompression
|
||||
public static class Format2
|
||||
{
|
||||
public static void DecodeInto(byte[] src, byte[] dest, int destIndex)
|
||||
{
|
||||
@@ -1,18 +1,16 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
namespace OpenRA.Mods.Common.FileFormats
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
// Data that is to be XORed against another set of data (aka Format40)
|
||||
public static class XORDeltaCompression
|
||||
public static class Format40
|
||||
{
|
||||
public static int DecodeInto(byte[] src, byte[] dest, int srcOffset)
|
||||
{
|
||||
@@ -1,18 +1,17 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace OpenRA.Mods.Common.FileFormats
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
class FastByteReader
|
||||
{
|
||||
@@ -42,8 +41,7 @@ namespace OpenRA.Mods.Common.FileFormats
|
||||
public int Remaining() { return src.Length - offset; }
|
||||
}
|
||||
|
||||
// Lempel - Castle - Welch algorithm (aka Format80)
|
||||
public static class LCWCompression
|
||||
public static class Format80
|
||||
{
|
||||
static void ReplicatePrevious(byte[] dest, int destIndex, int srcIndex, int count)
|
||||
{
|
||||
@@ -158,7 +156,7 @@ namespace OpenRA.Mods.Common.FileFormats
|
||||
}
|
||||
}
|
||||
|
||||
// Quick and dirty LCW encoder version 2
|
||||
// Quick and dirty Format80 encoder version 2
|
||||
// Uses raw copy and RLE compression
|
||||
public static byte[] Encode(byte[] src)
|
||||
{
|
||||
@@ -1,17 +1,17 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using OpenRA.Graphics;
|
||||
|
||||
namespace OpenRA.FileFormats
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace OpenRA.FileFormats
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
@@ -15,7 +14,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace OpenRA.Mods.Common.FileFormats
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
public class IniFile
|
||||
{
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
@@ -42,126 +41,114 @@ namespace OpenRA.FileFormats
|
||||
Color[] palette = null;
|
||||
var data = new List<byte>();
|
||||
|
||||
try
|
||||
for (;;)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
var length = IPAddress.NetworkToHostOrder(br.ReadInt32());
|
||||
var type = Encoding.UTF8.GetString(br.ReadBytes(4));
|
||||
var content = br.ReadBytes(length);
|
||||
/*var crc = */br.ReadInt32();
|
||||
var length = IPAddress.NetworkToHostOrder(br.ReadInt32());
|
||||
var type = Encoding.UTF8.GetString(br.ReadBytes(4));
|
||||
var content = br.ReadBytes(length);
|
||||
/*var crc = */br.ReadInt32();
|
||||
|
||||
if (bitmap == null && type != "IHDR")
|
||||
throw new InvalidDataException("Invalid PNG file - header does not appear first.");
|
||||
using (var ms = new MemoryStream(content))
|
||||
using (var cr = new BinaryReader(ms))
|
||||
switch (type)
|
||||
{
|
||||
case "IHDR":
|
||||
{
|
||||
var width = IPAddress.NetworkToHostOrder(cr.ReadInt32());
|
||||
var height = IPAddress.NetworkToHostOrder(cr.ReadInt32());
|
||||
var bitDepth = cr.ReadByte();
|
||||
var colorType = (PngColorType)cr.ReadByte();
|
||||
var compression = cr.ReadByte();
|
||||
/*var filter = */cr.ReadByte();
|
||||
var interlace = cr.ReadByte();
|
||||
|
||||
using (var ms = new MemoryStream(content))
|
||||
using (var cr = new BinaryReader(ms))
|
||||
switch (type)
|
||||
{
|
||||
case "IHDR":
|
||||
if (compression != 0) throw new InvalidDataException("Compression method not supported");
|
||||
if (interlace != 0) throw new InvalidDataException("Interlacing not supported");
|
||||
|
||||
bitmap = new Bitmap(width, height, MakePixelFormat(bitDepth, colorType));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "PLTE":
|
||||
{
|
||||
palette = new Color[256];
|
||||
for (var i = 0; i < 256; i++)
|
||||
{
|
||||
if (bitmap != null)
|
||||
throw new InvalidDataException("Invalid PNG file - duplicate header.");
|
||||
|
||||
var width = IPAddress.NetworkToHostOrder(cr.ReadInt32());
|
||||
var height = IPAddress.NetworkToHostOrder(cr.ReadInt32());
|
||||
var bitDepth = cr.ReadByte();
|
||||
var colorType = (PngColorType)cr.ReadByte();
|
||||
var compression = cr.ReadByte();
|
||||
/*var filter = */cr.ReadByte();
|
||||
var interlace = cr.ReadByte();
|
||||
|
||||
if (compression != 0) throw new InvalidDataException("Compression method not supported");
|
||||
if (interlace != 0) throw new InvalidDataException("Interlacing not supported");
|
||||
|
||||
bitmap = new Bitmap(width, height, MakePixelFormat(bitDepth, colorType));
|
||||
var r = cr.ReadByte(); var g = cr.ReadByte(); var b = cr.ReadByte();
|
||||
palette[i] = Color.FromArgb(r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
break;
|
||||
|
||||
case "PLTE":
|
||||
case "tRNS":
|
||||
{
|
||||
if (palette == null)
|
||||
throw new InvalidDataException("Non-Palette indexed PNG are not supported.");
|
||||
|
||||
for (var i = 0; i < length; i++)
|
||||
palette[i] = Color.FromArgb(cr.ReadByte(), palette[i]);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "IDAT":
|
||||
{
|
||||
data.AddRange(content);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "IEND":
|
||||
{
|
||||
if (bitmap == null)
|
||||
throw new InvalidDataException("Image header not found.");
|
||||
|
||||
var bits = bitmap.LockBits(bitmap.Bounds(),
|
||||
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
|
||||
|
||||
using (var ns = new MemoryStream(data.ToArray()))
|
||||
{
|
||||
palette = new Color[256];
|
||||
for (var i = 0; i < 256; i++)
|
||||
// 'zlib' flags bytes; confuses the DeflateStream.
|
||||
/*var flags = (byte)*/ns.ReadByte();
|
||||
/*var moreFlags = (byte)*/ns.ReadByte();
|
||||
|
||||
using (var ds = new DeflateStream(ns, CompressionMode.Decompress))
|
||||
using (var dr = new BinaryReader(ds))
|
||||
{
|
||||
var r = cr.ReadByte(); var g = cr.ReadByte(); var b = cr.ReadByte();
|
||||
palette[i] = Color.FromArgb(r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "tRNS":
|
||||
{
|
||||
if (palette == null)
|
||||
throw new InvalidDataException("Non-Palette indexed PNG are not supported.");
|
||||
|
||||
for (var i = 0; i < length; i++)
|
||||
palette[i] = Color.FromArgb(cr.ReadByte(), palette[i]);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "IDAT":
|
||||
{
|
||||
data.AddRange(content);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "IEND":
|
||||
{
|
||||
var bits = bitmap.LockBits(bitmap.Bounds(),
|
||||
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
|
||||
|
||||
using (var ns = new MemoryStream(data.ToArray()))
|
||||
{
|
||||
// 'zlib' flags bytes; confuses the DeflateStream.
|
||||
/*var flags = (byte)*/ns.ReadByte();
|
||||
/*var moreFlags = (byte)*/ns.ReadByte();
|
||||
|
||||
using (var ds = new DeflateStream(ns, CompressionMode.Decompress))
|
||||
using (var dr = new BinaryReader(ds))
|
||||
var prevLine = new byte[bitmap.Width]; // all zero
|
||||
for (var y = 0; y < bitmap.Height; y++)
|
||||
{
|
||||
var prevLine = new byte[bitmap.Width]; // all zero
|
||||
for (var y = 0; y < bitmap.Height; y++)
|
||||
{
|
||||
var filter = (PngFilter)dr.ReadByte();
|
||||
var line = dr.ReadBytes(bitmap.Width);
|
||||
var filter = (PngFilter)dr.ReadByte();
|
||||
var line = dr.ReadBytes(bitmap.Width);
|
||||
|
||||
for (var i = 0; i < bitmap.Width; i++)
|
||||
line[i] = i > 0
|
||||
? UnapplyFilter(filter, line[i], line[i - 1], prevLine[i], prevLine[i - 1])
|
||||
: UnapplyFilter(filter, line[i], 0, prevLine[i], 0);
|
||||
for (var i = 0; i < bitmap.Width; i++)
|
||||
line[i] = i > 0
|
||||
? UnapplyFilter(filter, line[i], line[i - 1], prevLine[i], prevLine[i - 1])
|
||||
: UnapplyFilter(filter, line[i], 0, prevLine[i], 0);
|
||||
|
||||
Marshal.Copy(line, 0, new IntPtr(bits.Scan0.ToInt64() + y * bits.Stride), line.Length);
|
||||
prevLine = line;
|
||||
}
|
||||
Marshal.Copy(line, 0, new IntPtr(bits.Scan0.ToInt64() + y * bits.Stride), line.Length);
|
||||
prevLine = line;
|
||||
}
|
||||
}
|
||||
|
||||
bitmap.UnlockBits(bits);
|
||||
|
||||
if (palette == null)
|
||||
throw new InvalidDataException("Non-Palette indexed PNG are not supported.");
|
||||
|
||||
using (var temp = new Bitmap(1, 1, PixelFormat.Format8bppIndexed))
|
||||
{
|
||||
var cp = temp.Palette;
|
||||
for (var i = 0; i < 256; i++)
|
||||
cp.Entries[i] = palette[i]; // finalize the palette.
|
||||
bitmap.Palette = cp;
|
||||
return bitmap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (bitmap != null)
|
||||
bitmap.Dispose();
|
||||
throw;
|
||||
|
||||
bitmap.UnlockBits(bits);
|
||||
|
||||
if (palette == null)
|
||||
throw new InvalidDataException("Non-Palette indexed PNG are not supported.");
|
||||
|
||||
using (var temp = new Bitmap(1, 1, PixelFormat.Format8bppIndexed))
|
||||
{
|
||||
var cp = temp.Palette;
|
||||
for (var i = 0; i < 256; i++)
|
||||
cp.Entries[i] = palette[i]; // finalize the palette.
|
||||
bitmap.Palette = cp;
|
||||
return bitmap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -200,7 +187,7 @@ namespace OpenRA.FileFormats
|
||||
if (bitDepth == 8 && colorType == (PngColorType.Indexed | PngColorType.Color))
|
||||
return PixelFormat.Format8bppIndexed;
|
||||
|
||||
throw new InvalidDataException("Unknown pixel format");
|
||||
throw new InvalidDataException("Unknown pixelformat");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,360 +0,0 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
public class VocLoader : ISoundLoader
|
||||
{
|
||||
bool ISoundLoader.TryParseSound(Stream stream, out ISoundFormat sound)
|
||||
{
|
||||
try
|
||||
{
|
||||
sound = new VocFormat(stream);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Not a (supported) WAV
|
||||
}
|
||||
|
||||
sound = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public class VocFormat : ISoundFormat
|
||||
{
|
||||
public int SampleBits { get { return 8; } }
|
||||
public int Channels { get { return 1; } }
|
||||
public int SampleRate { get; private set; }
|
||||
public float LengthInSeconds { get { return (float)totalSamples / SampleRate; } }
|
||||
public Stream GetPCMInputStream() { return new VocStream(this); }
|
||||
|
||||
int totalSamples = 0;
|
||||
int samplePosition = 0;
|
||||
|
||||
Stream stream;
|
||||
List<VocBlock> blocks = new List<VocBlock>();
|
||||
IEnumerator<VocBlock> currentBlock;
|
||||
int samplesLeftInBlock = 0;
|
||||
byte[] buffer = new byte[4096];
|
||||
|
||||
struct VocFileHeader
|
||||
{
|
||||
public string Description;
|
||||
public int DatablockOffset;
|
||||
public int Version;
|
||||
public int ID;
|
||||
|
||||
public static VocFileHeader Read(Stream s)
|
||||
{
|
||||
VocFileHeader vfh;
|
||||
vfh.Description = s.ReadASCII(20);
|
||||
vfh.DatablockOffset = s.ReadUInt16();
|
||||
vfh.Version = s.ReadUInt16();
|
||||
vfh.ID = s.ReadUInt16();
|
||||
return vfh;
|
||||
}
|
||||
}
|
||||
|
||||
struct VocBlock
|
||||
{
|
||||
public int Code;
|
||||
public int Length;
|
||||
public VocSampleBlock SampleBlock;
|
||||
public VocLoopBlock LoopBlock;
|
||||
}
|
||||
|
||||
struct VocSampleBlock
|
||||
{
|
||||
public int Rate;
|
||||
public int Samples;
|
||||
public long Offset;
|
||||
}
|
||||
|
||||
struct VocLoopBlock
|
||||
{
|
||||
public int Count;
|
||||
}
|
||||
|
||||
public VocFormat(Stream stream)
|
||||
{
|
||||
this.stream = stream;
|
||||
|
||||
CheckVocHeader();
|
||||
Preload();
|
||||
}
|
||||
|
||||
void CheckVocHeader()
|
||||
{
|
||||
var vfh = VocFileHeader.Read(stream);
|
||||
|
||||
if (!vfh.Description.StartsWith("Creative Voice File"))
|
||||
throw new InvalidDataException("Voc header description not recognized");
|
||||
if (vfh.DatablockOffset != 26)
|
||||
throw new InvalidDataException("Voc header offset is wrong");
|
||||
if (vfh.Version != 0x010A)
|
||||
throw new InvalidDataException("Voc header version not recognized");
|
||||
if (vfh.ID != ~vfh.Version + 0x1234)
|
||||
throw new InvalidDataException("Voc header id is bogus - expected: " +
|
||||
(~vfh.Version + 0x1234).ToString("X") + " but value is : " + vfh.ID.ToString("X"));
|
||||
}
|
||||
|
||||
int GetSampleRateFromVocRate(int vocSampleRate)
|
||||
{
|
||||
if (vocSampleRate == 256)
|
||||
throw new InvalidDataException("Invalid frequency divisor 256 in voc file");
|
||||
if (vocSampleRate == 0xa5 || vocSampleRate == 0xa6)
|
||||
return 11025;
|
||||
else if (vocSampleRate == 0xd2 || vocSampleRate == 0xd3)
|
||||
return 22050;
|
||||
else
|
||||
return (int)(1000000L / (256L - vocSampleRate));
|
||||
}
|
||||
|
||||
void Preload()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
VocBlock block = new VocBlock();
|
||||
try
|
||||
{
|
||||
block.Code = stream.ReadByte();
|
||||
block.Length = 0;
|
||||
}
|
||||
catch (EndOfStreamException)
|
||||
{
|
||||
// Stream is allowed to end without a last block
|
||||
break;
|
||||
}
|
||||
|
||||
if (block.Code == 0 || block.Code > 9)
|
||||
break;
|
||||
|
||||
block.Length = stream.ReadByte();
|
||||
block.Length |= stream.ReadByte() << 8;
|
||||
block.Length |= stream.ReadByte() << 16;
|
||||
|
||||
var skip = 0;
|
||||
switch (block.Code)
|
||||
{
|
||||
// Sound data
|
||||
case 1:
|
||||
{
|
||||
if (block.Length < 2)
|
||||
throw new InvalidDataException("Invalid sound data block length in voc file");
|
||||
var freqDiv = stream.ReadByte();
|
||||
block.SampleBlock.Rate = GetSampleRateFromVocRate(freqDiv);
|
||||
var codec = stream.ReadByte();
|
||||
if (codec != 0)
|
||||
throw new InvalidDataException("Unhandled codec used in voc file");
|
||||
skip = block.Length - 2;
|
||||
block.SampleBlock.Samples = skip;
|
||||
block.SampleBlock.Offset = stream.Position;
|
||||
|
||||
// See if last block contained additional information
|
||||
if (blocks.Count > 0)
|
||||
{
|
||||
var b = blocks.Last();
|
||||
if (b.Code == 8)
|
||||
{
|
||||
block.SampleBlock.Rate = b.SampleBlock.Rate;
|
||||
blocks.Remove(b);
|
||||
}
|
||||
}
|
||||
|
||||
SampleRate = Math.Max(SampleRate, block.SampleBlock.Rate);
|
||||
break;
|
||||
}
|
||||
|
||||
// Silence
|
||||
case 3:
|
||||
{
|
||||
if (block.Length != 3)
|
||||
throw new InvalidDataException("Invalid silence block length in voc file");
|
||||
block.SampleBlock.Offset = 0;
|
||||
block.SampleBlock.Samples = stream.ReadUInt16() + 1;
|
||||
var freqDiv = stream.ReadByte();
|
||||
block.SampleBlock.Rate = GetSampleRateFromVocRate(freqDiv);
|
||||
break;
|
||||
}
|
||||
|
||||
// Repeat start
|
||||
case 6:
|
||||
{
|
||||
if (block.Length != 2)
|
||||
throw new InvalidDataException("Invalid repeat start block length in voc file");
|
||||
block.LoopBlock.Count = stream.ReadUInt16() + 1;
|
||||
break;
|
||||
}
|
||||
|
||||
// Repeat end
|
||||
case 7:
|
||||
break;
|
||||
|
||||
// Extra info
|
||||
case 8:
|
||||
{
|
||||
if (block.Length != 4)
|
||||
throw new InvalidDataException("Invalid info block length in voc file");
|
||||
int freqDiv = stream.ReadUInt16();
|
||||
if (freqDiv == 65536)
|
||||
throw new InvalidDataException("Invalid frequency divisor 65536 in voc file");
|
||||
var codec = stream.ReadByte();
|
||||
if (codec != 0)
|
||||
throw new InvalidDataException("Unhandled codec used in voc file");
|
||||
var channels = stream.ReadByte() + 1;
|
||||
if (channels != 1)
|
||||
throw new InvalidDataException("Unhandled number of channels in voc file");
|
||||
block.SampleBlock.Offset = 0;
|
||||
block.SampleBlock.Samples = 0;
|
||||
block.SampleBlock.Rate = (int)(256000000L / (65536L - freqDiv));
|
||||
break;
|
||||
}
|
||||
|
||||
// Sound data (New format)
|
||||
case 9:
|
||||
default:
|
||||
throw new InvalidDataException("Unhandled code in voc file");
|
||||
}
|
||||
|
||||
if (skip > 0)
|
||||
stream.Seek(skip, SeekOrigin.Current);
|
||||
blocks.Add(block);
|
||||
}
|
||||
|
||||
// Check validity and calculated total number of samples
|
||||
foreach (var b in blocks)
|
||||
{
|
||||
if (b.Code == 8)
|
||||
throw new InvalidDataException("Unused block 8 in voc file");
|
||||
if (b.Code != 1 && b.Code != 9)
|
||||
continue;
|
||||
if (b.SampleBlock.Rate != SampleRate)
|
||||
throw new InvalidDataException("Voc file contains chunks with different sample rate");
|
||||
totalSamples += b.SampleBlock.Samples;
|
||||
}
|
||||
|
||||
Rewind();
|
||||
}
|
||||
|
||||
void Rewind()
|
||||
{
|
||||
currentBlock = blocks.GetEnumerator();
|
||||
samplesLeftInBlock = 0;
|
||||
samplePosition = 0;
|
||||
|
||||
while (currentBlock.MoveNext())
|
||||
{
|
||||
if (currentBlock.Current.Code == 1)
|
||||
{
|
||||
stream.Seek(currentBlock.Current.SampleBlock.Offset, SeekOrigin.Begin);
|
||||
samplesLeftInBlock = currentBlock.Current.SampleBlock.Samples;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool EndOfData { get { return currentBlock.Current.Equals(blocks.Last()) && samplesLeftInBlock == 0; } }
|
||||
|
||||
int FillBuffer(int maxSamples)
|
||||
{
|
||||
var bufferedSamples = 0;
|
||||
var offset = 0;
|
||||
|
||||
maxSamples = Math.Min(buffer.Length, maxSamples);
|
||||
|
||||
while (maxSamples > 0 && !EndOfData)
|
||||
{
|
||||
var len = Math.Min(maxSamples, samplesLeftInBlock);
|
||||
stream.ReadBytes(buffer, offset, len);
|
||||
offset += len;
|
||||
var samplesRead = len;
|
||||
bufferedSamples += samplesRead;
|
||||
maxSamples -= samplesRead;
|
||||
samplesLeftInBlock -= samplesRead;
|
||||
samplePosition += len;
|
||||
|
||||
UpdateBlockIfNeeded();
|
||||
}
|
||||
|
||||
return bufferedSamples;
|
||||
}
|
||||
|
||||
void UpdateBlockIfNeeded()
|
||||
{
|
||||
if (samplesLeftInBlock == 0)
|
||||
{
|
||||
while (currentBlock.MoveNext())
|
||||
{
|
||||
if (currentBlock.Current.Code != 1 && currentBlock.Current.Code != 9)
|
||||
continue;
|
||||
stream.Seek(currentBlock.Current.SampleBlock.Offset, SeekOrigin.Begin);
|
||||
samplesLeftInBlock = currentBlock.Current.SampleBlock.Samples;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
var bytesWritten = 0;
|
||||
var samplesLeft = Math.Min(count, buffer.Length - offset);
|
||||
while (samplesLeft > 0)
|
||||
{
|
||||
var len = FillBuffer(samplesLeft);
|
||||
if (len == 0)
|
||||
break;
|
||||
Buffer.BlockCopy(this.buffer, 0, buffer, offset, len);
|
||||
samplesLeft -= len;
|
||||
offset += len;
|
||||
bytesWritten += len;
|
||||
}
|
||||
|
||||
return bytesWritten;
|
||||
}
|
||||
|
||||
public class VocStream : Stream
|
||||
{
|
||||
VocFormat format;
|
||||
public VocStream(VocFormat format)
|
||||
{
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
public override bool CanRead { get { return format.samplePosition < format.totalSamples; } }
|
||||
public override bool CanSeek { get { return false; } }
|
||||
public override bool CanWrite { get { return false; } }
|
||||
|
||||
public override long Length { get { return format.totalSamples; } }
|
||||
public override long Position
|
||||
{
|
||||
get { return format.samplePosition; }
|
||||
set { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
return format.Read(buffer, offset, count);
|
||||
}
|
||||
|
||||
public override void Flush() { throw new NotImplementedException(); }
|
||||
public override long Seek(long offset, SeekOrigin origin) { throw new NotImplementedException(); }
|
||||
public override void SetLength(long value) { throw new NotImplementedException(); }
|
||||
public override void Write(byte[] buffer, int offset, int count) { throw new NotImplementedException(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,17 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using OpenRA.FileFormats;
|
||||
|
||||
namespace OpenRA.Mods.Common.FileFormats
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
public class VqaReader
|
||||
{
|
||||
@@ -221,7 +219,7 @@ namespace OpenRA.Mods.Common.FileFormats
|
||||
}
|
||||
|
||||
if (audioChannels == 1)
|
||||
audioData = compressed ? AudReader.LoadSound(audio1.ToArray(), ref adpcmIndex) : audio1.ToArray();
|
||||
audioData = compressed ? AudLoader.LoadSound(audio1.ToArray(), ref adpcmIndex) : audio1.ToArray();
|
||||
else
|
||||
{
|
||||
byte[] leftData, rightData;
|
||||
@@ -233,9 +231,9 @@ namespace OpenRA.Mods.Common.FileFormats
|
||||
else
|
||||
{
|
||||
adpcmIndex = 0;
|
||||
leftData = AudReader.LoadSound(audio1.ToArray(), ref adpcmIndex);
|
||||
leftData = AudLoader.LoadSound(audio1.ToArray(), ref adpcmIndex);
|
||||
adpcmIndex = 0;
|
||||
rightData = AudReader.LoadSound(audio2.ToArray(), ref adpcmIndex);
|
||||
rightData = AudLoader.LoadSound(audio2.ToArray(), ref adpcmIndex);
|
||||
}
|
||||
|
||||
audioData = new byte[rightData.Length + leftData.Length];
|
||||
@@ -331,7 +329,7 @@ namespace OpenRA.Mods.Common.FileFormats
|
||||
Array.Clear(cbf, 0, cbf.Length);
|
||||
Array.Clear(cbfBuffer, 0, cbfBuffer.Length);
|
||||
var decodeCount = 0;
|
||||
decodeCount = LCWCompression.DecodeInto(fileBuffer, cbfBuffer, decodeMode ? 1 : 0, decodeMode);
|
||||
decodeCount = Format80.DecodeInto(fileBuffer, cbfBuffer, decodeMode ? 1 : 0, decodeMode);
|
||||
if ((videoFlags & 0x10) == 16)
|
||||
{
|
||||
var p = 0;
|
||||
@@ -367,7 +365,7 @@ namespace OpenRA.Mods.Common.FileFormats
|
||||
if (type == "CBP0")
|
||||
cbf = (byte[])cbp.Clone();
|
||||
else
|
||||
LCWCompression.DecodeInto(cbp, cbf);
|
||||
Format80.DecodeInto(cbp, cbf);
|
||||
|
||||
chunkBufferOffset = currentChunkBuffer = 0;
|
||||
}
|
||||
@@ -392,7 +390,7 @@ namespace OpenRA.Mods.Common.FileFormats
|
||||
|
||||
// Frame data
|
||||
case "VPTZ":
|
||||
LCWCompression.DecodeInto(s.ReadBytes(subchunkLength), origData);
|
||||
Format80.DecodeInto(s.ReadBytes(subchunkLength), origData);
|
||||
|
||||
// This is the last subchunk
|
||||
return;
|
||||
@@ -400,9 +398,9 @@ namespace OpenRA.Mods.Common.FileFormats
|
||||
Array.Clear(origData, 0, origData.Length);
|
||||
s.ReadBytes(fileBuffer, 0, subchunkLength);
|
||||
if (fileBuffer[0] != 0)
|
||||
vtprSize = LCWCompression.DecodeInto(fileBuffer, origData);
|
||||
vtprSize = Format80.DecodeInto(fileBuffer, origData);
|
||||
else
|
||||
LCWCompression.DecodeInto(fileBuffer, origData, 1, true);
|
||||
Format80.DecodeInto(fileBuffer, origData, 1, true);
|
||||
return;
|
||||
case "VPTR":
|
||||
Array.Clear(origData, 0, origData.Length);
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
@@ -14,120 +13,48 @@ using System.IO;
|
||||
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
public class WavLoader : ISoundLoader
|
||||
public class WavLoader
|
||||
{
|
||||
bool IsWave(Stream s)
|
||||
{
|
||||
var start = s.Position;
|
||||
var type = s.ReadASCII(4);
|
||||
s.Position += 4;
|
||||
var format = s.ReadASCII(4);
|
||||
s.Position = start;
|
||||
public readonly int FileSize;
|
||||
public readonly string Format;
|
||||
|
||||
return type == "RIFF" && format == "WAVE";
|
||||
}
|
||||
public readonly int FmtChunkSize;
|
||||
public readonly int AudioFormat;
|
||||
public readonly int Channels;
|
||||
public readonly int SampleRate;
|
||||
public readonly int ByteRate;
|
||||
public readonly int BlockAlign;
|
||||
public readonly int BitsPerSample;
|
||||
|
||||
bool ISoundLoader.TryParseSound(Stream stream, out ISoundFormat sound)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (IsWave(stream))
|
||||
{
|
||||
sound = new WavFormat(stream);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Not a (supported) WAV
|
||||
}
|
||||
|
||||
sound = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public class WavFormat : ISoundFormat
|
||||
{
|
||||
public int Channels { get { return reader.Value.Channels; } }
|
||||
public int SampleBits { get { return reader.Value.BitsPerSample; } }
|
||||
public int SampleRate { get { return reader.Value.SampleRate; } }
|
||||
public float LengthInSeconds { get { return WavReader.WaveLength(stream); } }
|
||||
public Stream GetPCMInputStream() { return new MemoryStream(reader.Value.RawOutput); }
|
||||
|
||||
Lazy<WavReader> reader;
|
||||
|
||||
readonly Stream stream;
|
||||
|
||||
public WavFormat(Stream stream)
|
||||
{
|
||||
this.stream = stream;
|
||||
|
||||
var position = stream.Position;
|
||||
reader = Exts.Lazy(() =>
|
||||
{
|
||||
var wavReader = new WavReader();
|
||||
try
|
||||
{
|
||||
if (!wavReader.LoadSound(stream))
|
||||
throw new InvalidDataException();
|
||||
}
|
||||
finally
|
||||
{
|
||||
stream.Position = position;
|
||||
}
|
||||
|
||||
return wavReader;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class WavReader
|
||||
{
|
||||
public int FileSize;
|
||||
public string Format;
|
||||
|
||||
public int FmtChunkSize;
|
||||
public int AudioFormat;
|
||||
public int Channels;
|
||||
public int SampleRate;
|
||||
public int ByteRate;
|
||||
public int BlockAlign;
|
||||
public int BitsPerSample;
|
||||
|
||||
public int UncompressedSize;
|
||||
public int DataSize;
|
||||
public byte[] RawOutput;
|
||||
public readonly int UncompressedSize;
|
||||
public readonly int DataSize;
|
||||
public readonly byte[] RawOutput;
|
||||
|
||||
public enum WaveType { Pcm = 0x1, ImaAdpcm = 0x11 }
|
||||
public static WaveType Type { get; private set; }
|
||||
|
||||
public bool LoadSound(Stream s)
|
||||
public WavLoader(Stream s)
|
||||
{
|
||||
var type = s.ReadASCII(4);
|
||||
if (type != "RIFF")
|
||||
return false;
|
||||
|
||||
FileSize = s.ReadInt32();
|
||||
Format = s.ReadASCII(4);
|
||||
if (Format != "WAVE")
|
||||
return false;
|
||||
while (s.Position < s.Length)
|
||||
{
|
||||
if ((s.Position & 1) == 1)
|
||||
s.ReadByte(); // Alignment
|
||||
|
||||
type = s.ReadASCII(4);
|
||||
var type = s.ReadASCII(4);
|
||||
switch (type)
|
||||
{
|
||||
case "RIFF":
|
||||
FileSize = s.ReadInt32();
|
||||
Format = s.ReadASCII(4);
|
||||
if (Format != "WAVE")
|
||||
throw new NotSupportedException("Not a canonical WAVE file.");
|
||||
break;
|
||||
case "fmt ":
|
||||
FmtChunkSize = s.ReadInt32();
|
||||
AudioFormat = s.ReadInt16();
|
||||
Type = (WaveType)AudioFormat;
|
||||
|
||||
if (!Enum.IsDefined(typeof(WaveType), Type))
|
||||
throw new NotSupportedException("Compression type {0} is not supported.".F(AudioFormat));
|
||||
|
||||
if (Type != WaveType.Pcm && Type != WaveType.ImaAdpcm)
|
||||
throw new NotSupportedException("Compression type is not supported.");
|
||||
Channels = s.ReadInt16();
|
||||
SampleRate = s.ReadInt32();
|
||||
ByteRate = s.ReadInt32();
|
||||
@@ -137,17 +64,24 @@ namespace OpenRA.FileFormats
|
||||
s.ReadBytes(FmtChunkSize - 16);
|
||||
break;
|
||||
case "fact":
|
||||
var chunkSize = s.ReadInt32();
|
||||
UncompressedSize = s.ReadInt32();
|
||||
s.ReadBytes(chunkSize - 4);
|
||||
{
|
||||
var chunkSize = s.ReadInt32();
|
||||
UncompressedSize = s.ReadInt32();
|
||||
s.ReadBytes(chunkSize - 4);
|
||||
}
|
||||
|
||||
break;
|
||||
case "data":
|
||||
DataSize = s.ReadInt32();
|
||||
RawOutput = s.ReadBytes(DataSize);
|
||||
break;
|
||||
default:
|
||||
var unknownChunkSize = s.ReadInt32();
|
||||
s.ReadBytes(unknownChunkSize);
|
||||
// Ignore unknown chunks
|
||||
{
|
||||
var chunkSize = s.ReadInt32();
|
||||
s.ReadBytes(chunkSize);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -157,8 +91,6 @@ namespace OpenRA.FileFormats
|
||||
RawOutput = DecodeImaAdpcmData();
|
||||
BitsPerSample = 16;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static float WaveLength(Stream s)
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
@@ -20,21 +19,22 @@ namespace OpenRA.FileFormats
|
||||
public XccGlobalDatabase(Stream s)
|
||||
{
|
||||
var entries = new List<string>();
|
||||
while (s.Peek() > -1)
|
||||
var reader = new BinaryReader(s);
|
||||
while (reader.PeekChar() > -1)
|
||||
{
|
||||
var count = s.ReadInt32();
|
||||
var count = reader.ReadInt32();
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var chars = new List<char>();
|
||||
byte c;
|
||||
char c;
|
||||
|
||||
// Read filename
|
||||
while ((c = s.ReadUInt8()) != 0)
|
||||
chars.Add((char)c);
|
||||
while ((c = reader.ReadChar()) != 0)
|
||||
chars.Add(c);
|
||||
entries.Add(new string(chars.ToArray()));
|
||||
|
||||
// Skip comment
|
||||
while ((c = s.ReadUInt8()) != 0) { }
|
||||
while ((c = reader.ReadChar()) != 0) { }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
@@ -50,11 +49,11 @@ namespace OpenRA.FileFormats
|
||||
writer.Write(Encoding.ASCII.GetBytes("XCC by Olaf van der Spek"));
|
||||
writer.Write(new byte[] { 0x1A, 0x04, 0x17, 0x27, 0x10, 0x19, 0x80, 0x00 });
|
||||
|
||||
writer.Write(Entries.Aggregate(Entries.Length, (a, b) => a + b.Length) + 52); // Size
|
||||
writer.Write(0); // Type
|
||||
writer.Write(0); // Version
|
||||
writer.Write(0); // Game/Format (0 == TD)
|
||||
writer.Write(Entries.Length); // Entries
|
||||
writer.Write((int)(Entries.Aggregate(Entries.Length, (a, b) => a + b.Length) + 52)); // Size
|
||||
writer.Write((int)0); // Type
|
||||
writer.Write((int)0); // Version
|
||||
writer.Write((int)0); // Game/Format (0 == TD)
|
||||
writer.Write((int)Entries.Length); // Entries
|
||||
foreach (var e in Entries)
|
||||
{
|
||||
writer.Write(Encoding.ASCII.GetBytes(e));
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
@@ -20,17 +19,19 @@ using OpenRA.Primitives;
|
||||
|
||||
namespace OpenRA.FileSystem
|
||||
{
|
||||
public sealed class BagFile : IReadOnlyPackage
|
||||
public sealed class BagFile : IFolder
|
||||
{
|
||||
public string Name { get; private set; }
|
||||
public IEnumerable<string> Contents { get { return index.Keys; } }
|
||||
static readonly uint[] Nothing = { };
|
||||
|
||||
readonly string bagFilename;
|
||||
readonly Stream s;
|
||||
readonly Dictionary<string, IdxEntry> index;
|
||||
readonly int bagFilePriority;
|
||||
readonly Dictionary<uint, IdxEntry> index;
|
||||
|
||||
public BagFile(FileSystem context, string filename)
|
||||
public BagFile(string filename, int priority)
|
||||
{
|
||||
Name = filename;
|
||||
bagFilename = filename;
|
||||
bagFilePriority = priority;
|
||||
|
||||
// A bag file is always accompanied with an .idx counterpart
|
||||
// For example: audio.bag requires the audio.idx file
|
||||
@@ -38,20 +39,23 @@ namespace OpenRA.FileSystem
|
||||
|
||||
// Build the index and dispose the stream, it is no longer needed after this
|
||||
List<IdxEntry> entries;
|
||||
using (var indexStream = context.Open(indexFilename))
|
||||
using (var indexStream = GlobalFileSystem.Open(indexFilename))
|
||||
entries = new IdxReader(indexStream).Entries;
|
||||
|
||||
index = entries.ToDictionaryWithConflictLog(x => x.Filename,
|
||||
index = entries.ToDictionaryWithConflictLog(x => x.Hash,
|
||||
"{0} (bag format)".F(filename),
|
||||
null, x => "(offs={0}, len={1})".F(x.Offset, x.Length));
|
||||
|
||||
s = context.Open(filename);
|
||||
s = GlobalFileSystem.Open(filename);
|
||||
}
|
||||
|
||||
public Stream GetStream(string filename)
|
||||
public int Priority { get { return 1000 + bagFilePriority; } }
|
||||
public string Name { get { return bagFilename; } }
|
||||
|
||||
public Stream GetContent(uint hash)
|
||||
{
|
||||
IdxEntry entry;
|
||||
if (!index.TryGetValue(filename, out entry))
|
||||
if (!index.TryGetValue(hash, out entry))
|
||||
return null;
|
||||
|
||||
s.Seek(entry.Offset, SeekOrigin.Begin);
|
||||
@@ -68,7 +72,7 @@ namespace OpenRA.FileSystem
|
||||
waveHeaderMemoryStream.Write(Encoding.ASCII.GetBytes("WAVE"));
|
||||
waveHeaderMemoryStream.Write(Encoding.ASCII.GetBytes("fmt "));
|
||||
waveHeaderMemoryStream.Write(BitConverter.GetBytes(16));
|
||||
waveHeaderMemoryStream.Write(BitConverter.GetBytes((short)WavReader.WaveType.Pcm));
|
||||
waveHeaderMemoryStream.Write(BitConverter.GetBytes((short)WavLoader.WaveType.Pcm));
|
||||
waveHeaderMemoryStream.Write(BitConverter.GetBytes((short)channels));
|
||||
waveHeaderMemoryStream.Write(BitConverter.GetBytes(entry.SampleRate));
|
||||
waveHeaderMemoryStream.Write(BitConverter.GetBytes(2 * channels * entry.SampleRate));
|
||||
@@ -90,7 +94,7 @@ namespace OpenRA.FileSystem
|
||||
waveHeaderMemoryStream.Write(Encoding.ASCII.GetBytes("WAVE"));
|
||||
waveHeaderMemoryStream.Write(Encoding.ASCII.GetBytes("fmt "));
|
||||
waveHeaderMemoryStream.Write(BitConverter.GetBytes(20));
|
||||
waveHeaderMemoryStream.Write(BitConverter.GetBytes((short)WavReader.WaveType.ImaAdpcm));
|
||||
waveHeaderMemoryStream.Write(BitConverter.GetBytes((short)WavLoader.WaveType.ImaAdpcm));
|
||||
waveHeaderMemoryStream.Write(BitConverter.GetBytes((short)channels));
|
||||
waveHeaderMemoryStream.Write(BitConverter.GetBytes(entry.SampleRate));
|
||||
waveHeaderMemoryStream.Write(BitConverter.GetBytes(bytesPerSec));
|
||||
@@ -114,9 +118,65 @@ namespace OpenRA.FileSystem
|
||||
return mergedStream;
|
||||
}
|
||||
|
||||
public bool Contains(string filename)
|
||||
uint? FindMatchingHash(string filename)
|
||||
{
|
||||
return index.ContainsKey(filename);
|
||||
var hash = IdxEntry.HashFilename(filename, PackageHashType.CRC32);
|
||||
if (index.ContainsKey(hash))
|
||||
return hash;
|
||||
|
||||
// Maybe we were given a raw hash?
|
||||
uint raw;
|
||||
if (!uint.TryParse(filename, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out raw))
|
||||
return null;
|
||||
|
||||
if ("{0:X}".F(raw) == filename && index.ContainsKey(raw))
|
||||
return raw;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Stream GetContent(string filename)
|
||||
{
|
||||
var hash = FindMatchingHash(filename);
|
||||
return hash.HasValue ? GetContent(hash.Value) : null;
|
||||
}
|
||||
|
||||
public bool Exists(string filename)
|
||||
{
|
||||
return FindMatchingHash(filename).HasValue;
|
||||
}
|
||||
|
||||
public IEnumerable<uint> ClassicHashes()
|
||||
{
|
||||
return Nothing;
|
||||
}
|
||||
|
||||
public IEnumerable<uint> CrcHashes()
|
||||
{
|
||||
return index.Keys;
|
||||
}
|
||||
|
||||
public IEnumerable<string> AllFileNames()
|
||||
{
|
||||
var lookup = new Dictionary<uint, string>();
|
||||
if (GlobalFileSystem.Exists("global mix database.dat"))
|
||||
{
|
||||
var db = new XccGlobalDatabase(GlobalFileSystem.Open("global mix database.dat"));
|
||||
foreach (var e in db.Entries)
|
||||
{
|
||||
var hash = IdxEntry.HashFilename(e, PackageHashType.CRC32);
|
||||
if (!lookup.ContainsKey(hash))
|
||||
lookup.Add(hash, e);
|
||||
}
|
||||
}
|
||||
|
||||
return index.Keys.Select(k => lookup.ContainsKey(k) ? lookup[k] : "{0:X}".F(k));
|
||||
}
|
||||
|
||||
public void Write(Dictionary<string, byte[]> contents)
|
||||
{
|
||||
GlobalFileSystem.Unmount(this);
|
||||
throw new NotImplementedException("Updating bag files unsupported");
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
@@ -16,19 +15,19 @@ using System.Linq;
|
||||
|
||||
namespace OpenRA.FileSystem
|
||||
{
|
||||
public sealed class BigFile : IReadOnlyPackage
|
||||
public sealed class BigFile : IFolder
|
||||
{
|
||||
public string Name { get; private set; }
|
||||
public IEnumerable<string> Contents { get { return index.Keys; } }
|
||||
|
||||
readonly Dictionary<string, Entry> index = new Dictionary<string, Entry>();
|
||||
public int Priority { get; private set; }
|
||||
readonly Dictionary<string, Entry> entries = new Dictionary<string, Entry>();
|
||||
readonly Stream s;
|
||||
|
||||
public BigFile(FileSystem context, string filename)
|
||||
public BigFile(string filename, int priority)
|
||||
{
|
||||
Name = filename;
|
||||
Priority = priority;
|
||||
|
||||
s = context.Open(filename);
|
||||
s = GlobalFileSystem.Open(filename);
|
||||
try
|
||||
{
|
||||
if (s.ReadASCII(4) != "BIGF")
|
||||
@@ -48,7 +47,7 @@ namespace OpenRA.FileSystem
|
||||
for (var i = 0; i < entryCount; i++)
|
||||
{
|
||||
var entry = new Entry(s);
|
||||
index.Add(entry.Path, entry);
|
||||
entries.Add(entry.Path, entry);
|
||||
}
|
||||
}
|
||||
catch
|
||||
@@ -87,14 +86,34 @@ namespace OpenRA.FileSystem
|
||||
}
|
||||
}
|
||||
|
||||
public Stream GetStream(string filename)
|
||||
public Stream GetContent(string filename)
|
||||
{
|
||||
return index[filename].GetData();
|
||||
return entries[filename].GetData();
|
||||
}
|
||||
|
||||
public bool Contains(string filename)
|
||||
public bool Exists(string filename)
|
||||
{
|
||||
return index.ContainsKey(filename);
|
||||
return entries.ContainsKey(filename);
|
||||
}
|
||||
|
||||
public IEnumerable<uint> ClassicHashes()
|
||||
{
|
||||
return entries.Keys.Select(filename => PackageEntry.HashFilename(filename, PackageHashType.Classic));
|
||||
}
|
||||
|
||||
public IEnumerable<uint> CrcHashes()
|
||||
{
|
||||
return Enumerable.Empty<uint>();
|
||||
}
|
||||
|
||||
public IEnumerable<string> AllFileNames()
|
||||
{
|
||||
return entries.Keys;
|
||||
}
|
||||
|
||||
public void Write(Dictionary<string, byte[]> contents)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
||||
@@ -1,54 +1,51 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using OpenRA.Primitives;
|
||||
|
||||
namespace OpenRA.FileSystem
|
||||
{
|
||||
public sealed class D2kSoundResources : IReadOnlyPackage
|
||||
public sealed class D2kSoundResources : IFolder
|
||||
{
|
||||
struct Entry
|
||||
{
|
||||
public readonly uint Offset;
|
||||
public readonly uint Length;
|
||||
|
||||
public Entry(uint offset, uint length)
|
||||
{
|
||||
Offset = offset;
|
||||
Length = length;
|
||||
}
|
||||
}
|
||||
|
||||
public string Name { get; private set; }
|
||||
public IEnumerable<string> Contents { get { return index.Keys; } }
|
||||
|
||||
readonly Stream s;
|
||||
readonly Dictionary<string, Entry> index = new Dictionary<string, Entry>();
|
||||
|
||||
public D2kSoundResources(FileSystem context, string filename)
|
||||
readonly string filename;
|
||||
readonly List<string> filenames;
|
||||
readonly int priority;
|
||||
|
||||
readonly Dictionary<uint, PackageEntry> index = new Dictionary<uint, PackageEntry>();
|
||||
|
||||
public D2kSoundResources(string filename, int priority)
|
||||
{
|
||||
Name = filename;
|
||||
this.filename = filename;
|
||||
this.priority = priority;
|
||||
|
||||
s = context.Open(filename);
|
||||
s = GlobalFileSystem.Open(filename);
|
||||
try
|
||||
{
|
||||
filenames = new List<string>();
|
||||
|
||||
var headerLength = s.ReadUInt32();
|
||||
while (s.Position < headerLength + 4)
|
||||
{
|
||||
var name = s.ReadASCIIZ();
|
||||
var offset = s.ReadUInt32();
|
||||
var length = s.ReadUInt32();
|
||||
index.Add(name, new Entry(offset, length));
|
||||
|
||||
var hash = PackageEntry.HashFilename(name, PackageHashType.Classic);
|
||||
if (!index.ContainsKey(hash))
|
||||
index.Add(hash, new PackageEntry(hash, offset, length));
|
||||
|
||||
filenames.Add(name);
|
||||
}
|
||||
}
|
||||
catch
|
||||
@@ -58,19 +55,48 @@ namespace OpenRA.FileSystem
|
||||
}
|
||||
}
|
||||
|
||||
public Stream GetStream(string filename)
|
||||
public Stream GetContent(uint hash)
|
||||
{
|
||||
Entry e;
|
||||
if (!index.TryGetValue(filename, out e))
|
||||
PackageEntry e;
|
||||
if (!index.TryGetValue(hash, out e))
|
||||
return null;
|
||||
|
||||
s.Seek(e.Offset, SeekOrigin.Begin);
|
||||
return new MemoryStream(s.ReadBytes((int)e.Length));
|
||||
}
|
||||
|
||||
public bool Contains(string filename)
|
||||
public Stream GetContent(string filename)
|
||||
{
|
||||
return index.ContainsKey(filename);
|
||||
return GetContent(PackageEntry.HashFilename(filename, PackageHashType.Classic));
|
||||
}
|
||||
|
||||
public bool Exists(string filename)
|
||||
{
|
||||
return index.ContainsKey(PackageEntry.HashFilename(filename, PackageHashType.Classic));
|
||||
}
|
||||
|
||||
public IEnumerable<string> AllFileNames()
|
||||
{
|
||||
return filenames;
|
||||
}
|
||||
|
||||
public string Name { get { return filename; } }
|
||||
|
||||
public int Priority { get { return 1000 + priority; } }
|
||||
|
||||
public IEnumerable<uint> ClassicHashes()
|
||||
{
|
||||
return index.Keys;
|
||||
}
|
||||
|
||||
public IEnumerable<uint> CrcHashes()
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
public void Write(Dictionary<string, byte[]> contents)
|
||||
{
|
||||
throw new NotImplementedException("Cannot save Dune 2000 Sound Resources.");
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
||||
@@ -1,301 +0,0 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using OpenRA.Primitives;
|
||||
|
||||
namespace OpenRA.FileSystem
|
||||
{
|
||||
public interface IReadOnlyFileSystem
|
||||
{
|
||||
Stream Open(string filename);
|
||||
bool TryGetPackageContaining(string path, out IReadOnlyPackage package, out string filename);
|
||||
bool TryOpen(string filename, out Stream s);
|
||||
bool Exists(string filename);
|
||||
}
|
||||
|
||||
public class FileSystem : IReadOnlyFileSystem
|
||||
{
|
||||
public IEnumerable<IReadOnlyPackage> MountedPackages { get { return mountedPackages.Keys; } }
|
||||
readonly Dictionary<IReadOnlyPackage, int> mountedPackages = new Dictionary<IReadOnlyPackage, int>();
|
||||
readonly Dictionary<string, IReadOnlyPackage> explicitMounts = new Dictionary<string, IReadOnlyPackage>();
|
||||
|
||||
// Mod packages that should not be disposed
|
||||
readonly List<IReadOnlyPackage> modPackages = new List<IReadOnlyPackage>();
|
||||
|
||||
Cache<string, List<IReadOnlyPackage>> fileIndex = new Cache<string, List<IReadOnlyPackage>>(_ => new List<IReadOnlyPackage>());
|
||||
|
||||
public IReadOnlyPackage OpenPackage(string filename)
|
||||
{
|
||||
if (filename.EndsWith(".mix", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new MixFile(this, filename);
|
||||
if (filename.EndsWith(".zip", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new ZipFile(this, filename);
|
||||
if (filename.EndsWith(".oramap", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new ZipFile(this, filename);
|
||||
if (filename.EndsWith(".oramod", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new ZipFile(this, filename);
|
||||
if (filename.EndsWith(".RS", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new D2kSoundResources(this, filename);
|
||||
if (filename.EndsWith(".Z", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new InstallShieldPackage(this, filename);
|
||||
if (filename.EndsWith(".PAK", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new PakFile(this, filename);
|
||||
if (filename.EndsWith(".big", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new BigFile(this, filename);
|
||||
if (filename.EndsWith(".bag", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new BagFile(this, filename);
|
||||
if (filename.EndsWith(".hdr", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new InstallShieldCABExtractor(this, filename);
|
||||
|
||||
IReadOnlyPackage parent;
|
||||
string subPath = null;
|
||||
if (TryGetPackageContaining(filename, out parent, out subPath))
|
||||
return OpenPackage(subPath, parent);
|
||||
|
||||
return new Folder(Platform.ResolvePath(filename));
|
||||
}
|
||||
|
||||
public IReadOnlyPackage OpenPackage(string filename, IReadOnlyPackage parent)
|
||||
{
|
||||
// HACK: limit support to zip and folder until we generalize the PackageLoader support
|
||||
if (parent is Folder)
|
||||
{
|
||||
var path = Path.Combine(parent.Name, filename);
|
||||
|
||||
// HACK: work around SharpZipLib's lack of support for writing to in-memory files
|
||||
if (filename.EndsWith(".zip", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new ZipFile(this, path);
|
||||
if (filename.EndsWith(".oramap", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new ZipFile(this, path);
|
||||
|
||||
var subFolder = Platform.ResolvePath(path);
|
||||
if (Directory.Exists(subFolder))
|
||||
return new Folder(subFolder);
|
||||
}
|
||||
|
||||
if (filename.EndsWith(".zip", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new ZipFile(this, filename, parent.GetStream(filename));
|
||||
if (filename.EndsWith(".oramap", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new ZipFile(this, filename, parent.GetStream(filename));
|
||||
|
||||
if (parent is ZipFile)
|
||||
return new ZipFolder(this, (ZipFile)parent, filename, filename);
|
||||
|
||||
if (parent is ZipFolder)
|
||||
{
|
||||
var folder = (ZipFolder)parent;
|
||||
return new ZipFolder(this, folder.Parent, folder.Name + "/" + filename, filename);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public IReadWritePackage OpenWritablePackage(string filename)
|
||||
{
|
||||
if (filename.EndsWith(".zip", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new ZipFile(this, filename);
|
||||
if (filename.EndsWith(".oramap", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new ZipFile(this, filename);
|
||||
|
||||
return new Folder(filename);
|
||||
}
|
||||
|
||||
public void Mount(string name, string explicitName = null)
|
||||
{
|
||||
var optional = name.StartsWith("~");
|
||||
if (optional)
|
||||
name = name.Substring(1);
|
||||
|
||||
try
|
||||
{
|
||||
IReadOnlyPackage package;
|
||||
if (name.StartsWith("$"))
|
||||
{
|
||||
name = name.Substring(1);
|
||||
package = ModMetadata.AllMods[name].Package;
|
||||
modPackages.Add(package);
|
||||
}
|
||||
else
|
||||
package = OpenPackage(name);
|
||||
|
||||
Mount(package, explicitName);
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (!optional)
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void Mount(IReadOnlyPackage package, string explicitName = null)
|
||||
{
|
||||
var mountCount = 0;
|
||||
if (mountedPackages.TryGetValue(package, out mountCount))
|
||||
{
|
||||
// Package is already mounted
|
||||
// Increment the mount count and bump up the file loading priority
|
||||
mountedPackages[package] = mountCount + 1;
|
||||
foreach (var filename in package.Contents)
|
||||
{
|
||||
fileIndex[filename].Remove(package);
|
||||
fileIndex[filename].Add(package);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Mounting the package for the first time
|
||||
mountedPackages.Add(package, 1);
|
||||
|
||||
if (explicitName != null)
|
||||
explicitMounts.Add(explicitName, package);
|
||||
|
||||
foreach (var filename in package.Contents)
|
||||
fileIndex[filename].Add(package);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Unmount(IReadOnlyPackage package)
|
||||
{
|
||||
var mountCount = 0;
|
||||
if (!mountedPackages.TryGetValue(package, out mountCount))
|
||||
return false;
|
||||
|
||||
if (--mountCount <= 0)
|
||||
{
|
||||
foreach (var packagesForFile in fileIndex.Values)
|
||||
packagesForFile.RemoveAll(p => p == package);
|
||||
|
||||
mountedPackages.Remove(package);
|
||||
var explicitKeys = explicitMounts.Where(kv => kv.Value == package)
|
||||
.Select(kv => kv.Key)
|
||||
.ToList();
|
||||
|
||||
foreach (var key in explicitKeys)
|
||||
explicitMounts.Remove(key);
|
||||
|
||||
// Mod packages aren't owned by us, so we shouldn't dispose them
|
||||
if (modPackages.Contains(package))
|
||||
modPackages.Remove(package);
|
||||
else
|
||||
package.Dispose();
|
||||
}
|
||||
else
|
||||
mountedPackages[package] = mountCount;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void UnmountAll()
|
||||
{
|
||||
foreach (var package in mountedPackages.Keys)
|
||||
if (!modPackages.Contains(package))
|
||||
package.Dispose();
|
||||
|
||||
mountedPackages.Clear();
|
||||
explicitMounts.Clear();
|
||||
modPackages.Clear();
|
||||
|
||||
fileIndex = new Cache<string, List<IReadOnlyPackage>>(_ => new List<IReadOnlyPackage>());
|
||||
}
|
||||
|
||||
public void LoadFromManifest(Manifest manifest)
|
||||
{
|
||||
UnmountAll();
|
||||
foreach (var kv in manifest.Packages)
|
||||
Mount(kv.Key, kv.Value);
|
||||
}
|
||||
|
||||
Stream GetFromCache(string filename)
|
||||
{
|
||||
var package = fileIndex[filename]
|
||||
.LastOrDefault(x => x.Contains(filename));
|
||||
|
||||
if (package != null)
|
||||
return package.GetStream(filename);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Stream Open(string filename)
|
||||
{
|
||||
Stream s;
|
||||
if (!TryOpen(filename, out s))
|
||||
throw new FileNotFoundException("File not found: {0}".F(filename), filename);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
public bool TryGetPackageContaining(string path, out IReadOnlyPackage package, out string filename)
|
||||
{
|
||||
var explicitSplit = path.IndexOf('|');
|
||||
if (explicitSplit > 0 && explicitMounts.TryGetValue(path.Substring(0, explicitSplit), out package))
|
||||
{
|
||||
filename = path.Substring(explicitSplit + 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
package = fileIndex[path].LastOrDefault(x => x.Contains(path));
|
||||
filename = path;
|
||||
|
||||
return package != null;
|
||||
}
|
||||
|
||||
public bool TryOpen(string filename, out Stream s)
|
||||
{
|
||||
var explicitSplit = filename.IndexOf('|');
|
||||
if (explicitSplit > 0)
|
||||
{
|
||||
IReadOnlyPackage explicitPackage;
|
||||
if (explicitMounts.TryGetValue(filename.Substring(0, explicitSplit), out explicitPackage))
|
||||
{
|
||||
s = explicitPackage.GetStream(filename.Substring(explicitSplit + 1));
|
||||
if (s != null)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
s = GetFromCache(filename);
|
||||
if (s != null)
|
||||
return true;
|
||||
|
||||
// Ask each package individually
|
||||
// TODO: This fallback can be removed once the filesystem cleanups are complete
|
||||
var package = mountedPackages.Keys.LastOrDefault(x => x.Contains(filename));
|
||||
if (package != null)
|
||||
{
|
||||
s = package.GetStream(filename);
|
||||
return s != null;
|
||||
}
|
||||
|
||||
s = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Exists(string filename)
|
||||
{
|
||||
var explicitSplit = filename.IndexOf('|');
|
||||
if (explicitSplit > 0)
|
||||
{
|
||||
IReadOnlyPackage explicitPackage;
|
||||
if (explicitMounts.TryGetValue(filename.Substring(0, explicitSplit), out explicitPackage))
|
||||
if (explicitPackage.Contains(filename.Substring(explicitSplit + 1)))
|
||||
return true;
|
||||
}
|
||||
|
||||
return fileIndex.ContainsKey(filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
@@ -14,63 +13,70 @@ using System.IO;
|
||||
|
||||
namespace OpenRA.FileSystem
|
||||
{
|
||||
public sealed class Folder : IReadWritePackage
|
||||
public sealed class Folder : IFolder
|
||||
{
|
||||
readonly string path;
|
||||
readonly int priority;
|
||||
|
||||
public Folder(string path)
|
||||
// Create a new folder package
|
||||
public Folder(string path, int priority, Dictionary<string, byte[]> contents)
|
||||
{
|
||||
this.path = path;
|
||||
this.priority = priority;
|
||||
if (Directory.Exists(path))
|
||||
Directory.Delete(path, true);
|
||||
|
||||
Write(contents);
|
||||
}
|
||||
|
||||
public Folder(string path, int priority)
|
||||
{
|
||||
this.path = path;
|
||||
this.priority = priority;
|
||||
if (!Directory.Exists(path))
|
||||
Directory.CreateDirectory(path);
|
||||
}
|
||||
|
||||
public string Name { get { return path; } }
|
||||
|
||||
public IEnumerable<string> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (var filename in Directory.GetFiles(path, "*", SearchOption.TopDirectoryOnly))
|
||||
yield return Path.GetFileName(filename);
|
||||
foreach (var filename in Directory.GetDirectories(path))
|
||||
yield return Path.GetFileName(filename);
|
||||
}
|
||||
}
|
||||
|
||||
public Stream GetStream(string filename)
|
||||
public Stream GetContent(string filename)
|
||||
{
|
||||
try { return File.OpenRead(Path.Combine(path, filename)); }
|
||||
catch { return null; }
|
||||
}
|
||||
|
||||
public bool Contains(string filename)
|
||||
public IEnumerable<uint> ClassicHashes()
|
||||
{
|
||||
var combined = Path.Combine(path, filename);
|
||||
return combined.StartsWith(path) && File.Exists(combined);
|
||||
foreach (var filename in Directory.GetFiles(path, "*", SearchOption.TopDirectoryOnly))
|
||||
yield return PackageEntry.HashFilename(Path.GetFileName(filename), PackageHashType.Classic);
|
||||
}
|
||||
|
||||
public void Update(string filename, byte[] contents)
|
||||
public IEnumerable<uint> CrcHashes()
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
public IEnumerable<string> AllFileNames()
|
||||
{
|
||||
foreach (var filename in Directory.GetFiles(path, "*", SearchOption.TopDirectoryOnly))
|
||||
yield return Path.GetFileName(filename);
|
||||
}
|
||||
|
||||
public bool Exists(string filename)
|
||||
{
|
||||
return File.Exists(Path.Combine(path, filename));
|
||||
}
|
||||
|
||||
public int Priority { get { return priority; } }
|
||||
public string Name { get { return path; } }
|
||||
|
||||
public void Write(Dictionary<string, byte[]> contents)
|
||||
{
|
||||
if (!Directory.Exists(path))
|
||||
Directory.CreateDirectory(path);
|
||||
|
||||
using (var s = File.Create(Path.Combine(path, filename)))
|
||||
s.Write(contents, 0, contents.Length);
|
||||
}
|
||||
|
||||
public void Delete(string filename)
|
||||
{
|
||||
// HACK: ZipFiles can't be loaded as read-write from a stream, so we are
|
||||
// forced to bypass the parent package and load them with their full path
|
||||
// in FileSystem.OpenPackage. Their internal name therefore contains the
|
||||
// full parent path too. We need to be careful to not add a second path
|
||||
// prefix to these hacked packages.
|
||||
var filePath = filename.StartsWith(path) ? filename : Path.Combine(path, filename);
|
||||
if (Directory.Exists(filePath))
|
||||
Directory.Delete(filePath, true);
|
||||
else if (File.Exists(filePath))
|
||||
File.Delete(filePath);
|
||||
foreach (var file in contents)
|
||||
using (var dataStream = File.Create(Path.Combine(path, file.Key)))
|
||||
using (var writer = new BinaryWriter(dataStream))
|
||||
writer.Write(file.Value);
|
||||
}
|
||||
|
||||
public void Dispose() { }
|
||||
|
||||
273
OpenRA.Game/FileSystem/GlobalFileSystem.cs
Normal file
273
OpenRA.Game/FileSystem/GlobalFileSystem.cs
Normal file
@@ -0,0 +1,273 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2015 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 COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using OpenRA.Primitives;
|
||||
|
||||
namespace OpenRA.FileSystem
|
||||
{
|
||||
public interface IFolder : IDisposable
|
||||
{
|
||||
Stream GetContent(string filename);
|
||||
bool Exists(string filename);
|
||||
IEnumerable<uint> ClassicHashes();
|
||||
IEnumerable<uint> CrcHashes();
|
||||
IEnumerable<string> AllFileNames();
|
||||
void Write(Dictionary<string, byte[]> contents);
|
||||
int Priority { get; }
|
||||
string Name { get; }
|
||||
}
|
||||
|
||||
public static class GlobalFileSystem
|
||||
{
|
||||
public static List<IFolder> MountedFolders = new List<IFolder>();
|
||||
static Cache<uint, List<IFolder>> classicHashIndex = new Cache<uint, List<IFolder>>(_ => new List<IFolder>());
|
||||
static Cache<uint, List<IFolder>> crcHashIndex = new Cache<uint, List<IFolder>>(_ => new List<IFolder>());
|
||||
|
||||
public static List<string> FolderPaths = new List<string>();
|
||||
|
||||
static void MountInner(IFolder folder)
|
||||
{
|
||||
MountedFolders.Add(folder);
|
||||
|
||||
foreach (var hash in folder.ClassicHashes())
|
||||
{
|
||||
var l = classicHashIndex[hash];
|
||||
if (!l.Contains(folder))
|
||||
l.Add(folder);
|
||||
}
|
||||
|
||||
foreach (var hash in folder.CrcHashes())
|
||||
{
|
||||
var l = crcHashIndex[hash];
|
||||
if (!l.Contains(folder))
|
||||
l.Add(folder);
|
||||
}
|
||||
}
|
||||
|
||||
static int order = 0;
|
||||
|
||||
public static IFolder CreatePackage(string filename, int order, Dictionary<string, byte[]> content)
|
||||
{
|
||||
if (filename.EndsWith(".mix", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new MixFile(filename, order, content);
|
||||
if (filename.EndsWith(".zip", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new ZipFile(filename, order, content);
|
||||
if (filename.EndsWith(".oramap", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new ZipFile(filename, order, content);
|
||||
if (filename.EndsWith(".RS", StringComparison.InvariantCultureIgnoreCase))
|
||||
throw new NotImplementedException("The creation of .RS archives is unimplemented");
|
||||
if (filename.EndsWith(".Z", StringComparison.InvariantCultureIgnoreCase))
|
||||
throw new NotImplementedException("The creation of .Z archives is unimplemented");
|
||||
if (filename.EndsWith(".PAK", StringComparison.InvariantCultureIgnoreCase))
|
||||
throw new NotImplementedException("The creation of .PAK archives is unimplemented");
|
||||
if (filename.EndsWith(".big", StringComparison.InvariantCultureIgnoreCase))
|
||||
throw new NotImplementedException("The creation of .big archives is unimplemented");
|
||||
if (filename.EndsWith(".cab", StringComparison.InvariantCultureIgnoreCase))
|
||||
throw new NotImplementedException("The creation of .cab archives is unimplemented");
|
||||
|
||||
return new Folder(filename, order, content);
|
||||
}
|
||||
|
||||
public static IFolder OpenPackage(string filename, string annotation, int order)
|
||||
{
|
||||
if (filename.EndsWith(".mix", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
var type = string.IsNullOrEmpty(annotation)
|
||||
? PackageHashType.Classic
|
||||
: FieldLoader.GetValue<PackageHashType>("(value)", annotation);
|
||||
|
||||
return new MixFile(filename, type, order);
|
||||
}
|
||||
|
||||
if (filename.EndsWith(".zip", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new ZipFile(filename, order);
|
||||
if (filename.EndsWith(".oramap", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new ZipFile(filename, order);
|
||||
if (filename.EndsWith(".RS", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new D2kSoundResources(filename, order);
|
||||
if (filename.EndsWith(".Z", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new InstallShieldPackage(filename, order);
|
||||
if (filename.EndsWith(".PAK", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new PakFile(filename, order);
|
||||
if (filename.EndsWith(".big", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new BigFile(filename, order);
|
||||
if (filename.EndsWith(".bag", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new BagFile(filename, order);
|
||||
if (filename.EndsWith(".hdr", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new InstallShieldCABExtractor(filename, order);
|
||||
|
||||
return new Folder(filename, order);
|
||||
}
|
||||
|
||||
public static void Mount(string name, string annotation = null)
|
||||
{
|
||||
var optional = name.StartsWith("~");
|
||||
if (optional)
|
||||
name = name.Substring(1);
|
||||
|
||||
name = Platform.ResolvePath(name);
|
||||
|
||||
FolderPaths.Add(name);
|
||||
Action a = () => MountInner(OpenPackage(name, annotation, order++));
|
||||
|
||||
if (optional)
|
||||
try { a(); }
|
||||
catch { }
|
||||
else
|
||||
a();
|
||||
}
|
||||
|
||||
public static void UnmountAll()
|
||||
{
|
||||
foreach (var folder in MountedFolders)
|
||||
folder.Dispose();
|
||||
|
||||
MountedFolders.Clear();
|
||||
FolderPaths.Clear();
|
||||
classicHashIndex = new Cache<uint, List<IFolder>>(_ => new List<IFolder>());
|
||||
crcHashIndex = new Cache<uint, List<IFolder>>(_ => new List<IFolder>());
|
||||
}
|
||||
|
||||
public static bool Unmount(IFolder mount)
|
||||
{
|
||||
if (MountedFolders.Contains(mount))
|
||||
mount.Dispose();
|
||||
|
||||
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();
|
||||
foreach (var dir in manifest.Folders)
|
||||
Mount(dir);
|
||||
|
||||
foreach (var pkg in manifest.Packages)
|
||||
Mount(pkg.Key, pkg.Value);
|
||||
}
|
||||
|
||||
static Stream GetFromCache(PackageHashType type, string filename)
|
||||
{
|
||||
var index = type == PackageHashType.CRC32 ? crcHashIndex : classicHashIndex;
|
||||
var folder = index[PackageEntry.HashFilename(filename, type)]
|
||||
.Where(x => x.Exists(filename))
|
||||
.MinByOrDefault(x => x.Priority);
|
||||
|
||||
if (folder != null)
|
||||
return folder.GetContent(filename);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Stream Open(string filename)
|
||||
{
|
||||
Stream s;
|
||||
if (!TryOpen(filename, out s))
|
||||
throw new FileNotFoundException("File not found: {0}".F(filename), filename);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
public static bool TryOpen(string name, out Stream s)
|
||||
{
|
||||
var filename = name;
|
||||
var foldername = string.Empty;
|
||||
|
||||
// Used for faction specific packages; rule out false positive on Windows C:\ drive notation
|
||||
var explicitFolder = name.Contains(':') && !Directory.Exists(Path.GetDirectoryName(name));
|
||||
if (explicitFolder)
|
||||
{
|
||||
var divide = name.Split(':');
|
||||
foldername = divide.First();
|
||||
filename = divide.Last();
|
||||
}
|
||||
|
||||
// Check the cache for a quick lookup if the folder name is unknown
|
||||
// TODO: This disables caching for explicit folder requests
|
||||
if (filename.IndexOfAny(new char[] { '/', '\\' }) == -1 && !explicitFolder)
|
||||
{
|
||||
s = GetFromCache(PackageHashType.Classic, filename);
|
||||
if (s != null)
|
||||
return true;
|
||||
|
||||
s = GetFromCache(PackageHashType.CRC32, filename);
|
||||
if (s != null)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Ask each package individually
|
||||
IFolder folder;
|
||||
if (explicitFolder && !string.IsNullOrEmpty(foldername))
|
||||
folder = MountedFolders.Where(x => x.Name == foldername).MaxByOrDefault(x => x.Priority);
|
||||
else
|
||||
folder = MountedFolders.Where(x => x.Exists(filename)).MaxByOrDefault(x => x.Priority);
|
||||
|
||||
if (folder != null)
|
||||
{
|
||||
s = folder.GetContent(filename);
|
||||
return true;
|
||||
}
|
||||
|
||||
s = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool Exists(string name)
|
||||
{
|
||||
var explicitFolder = name.Contains(':') && !Directory.Exists(Path.GetDirectoryName(name));
|
||||
if (explicitFolder)
|
||||
{
|
||||
var divide = name.Split(':');
|
||||
var foldername = divide.First();
|
||||
var filename = divide.Last();
|
||||
return MountedFolders.Where(n => n.Name == foldername).Any(f => f.Exists(filename));
|
||||
}
|
||||
else
|
||||
return MountedFolders.Any(f => f.Exists(name));
|
||||
}
|
||||
|
||||
static Dictionary<string, Assembly> assemblyCache = new Dictionary<string, Assembly>();
|
||||
|
||||
public static Assembly ResolveAssembly(object sender, ResolveEventArgs e)
|
||||
{
|
||||
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
|
||||
if (assembly.FullName == e.Name)
|
||||
return assembly;
|
||||
|
||||
var frags = e.Name.Split(',');
|
||||
var filename = frags[0] + ".dll";
|
||||
|
||||
Assembly a;
|
||||
if (assemblyCache.TryGetValue(filename, out a))
|
||||
return a;
|
||||
|
||||
if (Exists(filename))
|
||||
using (var s = Open(filename))
|
||||
{
|
||||
var buf = s.ReadBytes((int)s.Length);
|
||||
a = Assembly.Load(buf);
|
||||
assemblyCache.Add(filename, a);
|
||||
return a;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace OpenRA.FileSystem
|
||||
{
|
||||
public interface IReadOnlyPackage : IDisposable
|
||||
{
|
||||
string Name { get; }
|
||||
IEnumerable<string> Contents { get; }
|
||||
Stream GetStream(string filename);
|
||||
bool Contains(string filename);
|
||||
}
|
||||
|
||||
public interface IReadWritePackage : IReadOnlyPackage
|
||||
{
|
||||
void Update(string filename, byte[] contents);
|
||||
void Delete(string filename);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
@@ -16,31 +15,80 @@ namespace OpenRA.FileSystem
|
||||
{
|
||||
public class IdxEntry
|
||||
{
|
||||
public readonly string Filename;
|
||||
public const string DefaultExtension = "wav";
|
||||
|
||||
public readonly uint Hash;
|
||||
public readonly string Name;
|
||||
public readonly string Extension;
|
||||
public readonly uint Offset;
|
||||
public readonly uint Length;
|
||||
public readonly uint SampleRate;
|
||||
public readonly uint Flags;
|
||||
public readonly uint ChunkSize;
|
||||
|
||||
public IdxEntry(uint hash, uint offset, uint length, uint sampleRate, uint flags, uint chuckSize)
|
||||
{
|
||||
Hash = hash;
|
||||
Offset = offset;
|
||||
Length = length;
|
||||
SampleRate = sampleRate;
|
||||
Flags = flags;
|
||||
ChunkSize = chuckSize;
|
||||
}
|
||||
|
||||
public IdxEntry(Stream s)
|
||||
{
|
||||
var name = s.ReadASCII(16);
|
||||
var pos = name.IndexOf('\0');
|
||||
if (pos != 0)
|
||||
name = name.Substring(0, pos);
|
||||
var asciiname = s.ReadASCII(16);
|
||||
|
||||
Filename = string.Concat(name, ".wav");
|
||||
var pos = asciiname.IndexOf('\0');
|
||||
if (pos != 0)
|
||||
asciiname = asciiname.Substring(0, pos);
|
||||
|
||||
Name = asciiname;
|
||||
Extension = DefaultExtension;
|
||||
Offset = s.ReadUInt32();
|
||||
Length = s.ReadUInt32();
|
||||
SampleRate = s.ReadUInt32();
|
||||
Flags = s.ReadUInt32();
|
||||
ChunkSize = s.ReadUInt32();
|
||||
Hash = HashFilename(string.Concat(Name, ".", Extension), PackageHashType.CRC32);
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(Name.PadRight(16, '\0'));
|
||||
w.Write(Offset);
|
||||
w.Write(Length);
|
||||
w.Write(SampleRate);
|
||||
w.Write(Flags);
|
||||
w.Write(ChunkSize);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "{0} - offset 0x{1:x8} - length 0x{2:x8}".F(Filename, Offset, Length);
|
||||
string filename;
|
||||
if (names.TryGetValue(Hash, out filename))
|
||||
return "{0} - offset 0x{1:x8} - length 0x{2:x8}".F(filename, Offset, Length);
|
||||
else
|
||||
return "0x{0:x8} - offset 0x{1:x8} - length 0x{2:x8}".F(Hash, Offset, Length);
|
||||
}
|
||||
|
||||
public static uint HashFilename(string name, PackageHashType type)
|
||||
{
|
||||
return PackageEntry.HashFilename(name, type);
|
||||
}
|
||||
|
||||
static Dictionary<uint, string> names = new Dictionary<uint, string>();
|
||||
|
||||
public static void AddStandardName(string s)
|
||||
{
|
||||
// RA1 and TD
|
||||
var hash = HashFilename(s, PackageHashType.Classic);
|
||||
names.Add(hash, s);
|
||||
|
||||
// TS
|
||||
var crcHash = HashFilename(s, PackageHashType.CRC32);
|
||||
names.Add(crcHash, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
@@ -15,10 +14,11 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using ICSharpCode.SharpZipLib.Zip.Compression;
|
||||
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
|
||||
|
||||
namespace OpenRA.FileSystem
|
||||
{
|
||||
public sealed class InstallShieldCABExtractor : IReadOnlyPackage
|
||||
public class InstallShieldCABExtractor : IDisposable, IFolder
|
||||
{
|
||||
const uint FileSplit = 0x1;
|
||||
const uint FileObfuscated = 0x2;
|
||||
@@ -44,7 +44,7 @@ namespace OpenRA.FileSystem
|
||||
FirstFile = reader.ReadUInt32();
|
||||
LastFile = reader.ReadUInt32();
|
||||
|
||||
reader.Seek(offset + nameOffset, SeekOrigin.Begin);
|
||||
reader.Seek(offset + (long)nameOffset, SeekOrigin.Begin);
|
||||
Name = reader.ReadASCIIZ();
|
||||
}
|
||||
}
|
||||
@@ -108,7 +108,7 @@ namespace OpenRA.FileSystem
|
||||
{
|
||||
Version = reader.ReadUInt32();
|
||||
VolumeInfo = reader.ReadUInt32();
|
||||
CabDescriptorOffset = reader.ReadUInt32();
|
||||
CabDescriptorOffset = (long)reader.ReadUInt32();
|
||||
CabDescriptorSize = reader.ReadUInt32();
|
||||
}
|
||||
}
|
||||
@@ -126,7 +126,7 @@ namespace OpenRA.FileSystem
|
||||
public CabDescriptor(Stream reader, CommonHeader commonHeader)
|
||||
{
|
||||
reader.Seek(commonHeader.CabDescriptorOffset + 12, SeekOrigin.Begin);
|
||||
FileTableOffset = reader.ReadUInt32();
|
||||
FileTableOffset = (long)reader.ReadUInt32();
|
||||
/* unknown */ reader.ReadUInt32();
|
||||
FileTableSize = reader.ReadUInt32();
|
||||
|
||||
@@ -135,7 +135,7 @@ namespace OpenRA.FileSystem
|
||||
/* unknown */ reader.ReadBytes(8);
|
||||
FileCount = reader.ReadUInt32();
|
||||
|
||||
FileTableOffset2 = reader.ReadUInt32();
|
||||
FileTableOffset2 = (long)reader.ReadUInt32();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,7 +187,6 @@ namespace OpenRA.FileSystem
|
||||
|
||||
class CabReader : IDisposable
|
||||
{
|
||||
readonly FileSystem context;
|
||||
readonly FileDescriptor fileDes;
|
||||
public uint RemainingArchiveStream;
|
||||
public uint RemainingFileStream;
|
||||
@@ -196,13 +195,12 @@ namespace OpenRA.FileSystem
|
||||
ushort volumeNumber;
|
||||
Stream cabFile;
|
||||
|
||||
public CabReader(FileSystem context, FileDescriptor fileDes, uint index, string commonName)
|
||||
public CabReader(FileDescriptor fileDes, uint index, string commonName)
|
||||
{
|
||||
this.fileDes = fileDes;
|
||||
this.index = index;
|
||||
this.commonName = commonName;
|
||||
this.context = context;
|
||||
volumeNumber = (ushort)(fileDes.Volume - 1u);
|
||||
volumeNumber = (ushort)((uint)fileDes.Volume - 1u);
|
||||
RemainingArchiveStream = 0;
|
||||
if ((fileDes.Flags & FileCompressed) > 0)
|
||||
RemainingFileStream = fileDes.CompressedSize;
|
||||
@@ -210,7 +208,7 @@ namespace OpenRA.FileSystem
|
||||
RemainingFileStream = fileDes.ExpandedSize;
|
||||
|
||||
cabFile = null;
|
||||
NextFile(context);
|
||||
NextFile();
|
||||
}
|
||||
|
||||
public void CopyTo(Stream dest)
|
||||
@@ -260,7 +258,7 @@ namespace OpenRA.FileSystem
|
||||
var read = cabFile.Read(outArray, 0, (int)RemainingArchiveStream);
|
||||
if (RemainingFileStream > RemainingArchiveStream)
|
||||
{
|
||||
NextFile(context);
|
||||
NextFile();
|
||||
RemainingArchiveStream -= (uint)cabFile.Read(outArray, read, (int)count - read);
|
||||
}
|
||||
|
||||
@@ -273,13 +271,13 @@ namespace OpenRA.FileSystem
|
||||
cabFile.Dispose();
|
||||
}
|
||||
|
||||
void NextFile(FileSystem context)
|
||||
public void NextFile()
|
||||
{
|
||||
if (cabFile != null)
|
||||
cabFile.Dispose();
|
||||
|
||||
++volumeNumber;
|
||||
cabFile = context.Open("{0}{1}.cab".F(commonName, volumeNumber));
|
||||
cabFile = GlobalFileSystem.Open("{0}{1}.cab".F(commonName, volumeNumber));
|
||||
if (cabFile.ReadUInt32() != 0x28635349)
|
||||
throw new InvalidDataException("Not an Installshield CAB package");
|
||||
|
||||
@@ -330,22 +328,23 @@ namespace OpenRA.FileSystem
|
||||
readonly List<uint> directoryTable;
|
||||
readonly Dictionary<uint, string> directoryNames = new Dictionary<uint, string>();
|
||||
readonly Dictionary<uint, FileDescriptor> fileDescriptors = new Dictionary<uint, FileDescriptor>();
|
||||
readonly Dictionary<string, uint> index = new Dictionary<string, uint>();
|
||||
readonly FileSystem context;
|
||||
readonly Dictionary<string, uint> fileLookup = new Dictionary<string, uint>();
|
||||
int priority;
|
||||
string commonName;
|
||||
public int Priority { get { return priority; } }
|
||||
|
||||
public string Name { get; private set; }
|
||||
public IEnumerable<string> Contents { get { return index.Keys; } }
|
||||
public string Name { get { return commonName; } }
|
||||
|
||||
public InstallShieldCABExtractor(FileSystem context, string hdrFilename)
|
||||
public InstallShieldCABExtractor(string hdrFilename, int priority = -1)
|
||||
{
|
||||
var fileGroups = new List<FileGroup>();
|
||||
var fileGroupOffsets = new List<uint>();
|
||||
|
||||
hdrFile = context.Open(hdrFilename);
|
||||
this.context = context;
|
||||
this.priority = priority;
|
||||
hdrFile = GlobalFileSystem.Open(hdrFilename);
|
||||
|
||||
// Strips archive number AND file extension
|
||||
Name = Regex.Replace(hdrFilename, @"\d*\.[^\.]*$", "");
|
||||
commonName = Regex.Replace(hdrFilename, @"\d*\.[^\.]*$", "");
|
||||
var signature = hdrFile.ReadUInt32();
|
||||
|
||||
if (signature != 0x28635349)
|
||||
@@ -372,7 +371,7 @@ namespace OpenRA.FileSystem
|
||||
hdrFile.Seek((long)nextOffset + 4 + commonHeader.CabDescriptorOffset, SeekOrigin.Begin);
|
||||
var descriptorOffset = hdrFile.ReadUInt32();
|
||||
nextOffset = hdrFile.ReadUInt32();
|
||||
hdrFile.Seek(descriptorOffset + commonHeader.CabDescriptorOffset, SeekOrigin.Begin);
|
||||
hdrFile.Seek((long)descriptorOffset + commonHeader.CabDescriptorOffset, SeekOrigin.Begin);
|
||||
|
||||
fileGroups.Add(new FileGroup(hdrFile, commonHeader.CabDescriptorOffset));
|
||||
}
|
||||
@@ -381,12 +380,12 @@ namespace OpenRA.FileSystem
|
||||
hdrFile.Seek(commonHeader.CabDescriptorOffset + cabDescriptor.FileTableOffset + cabDescriptor.FileTableOffset2, SeekOrigin.Begin);
|
||||
foreach (var fileGroup in fileGroups)
|
||||
{
|
||||
for (var i = fileGroup.FirstFile; i <= fileGroup.LastFile; ++i)
|
||||
for (var index = fileGroup.FirstFile; index <= fileGroup.LastFile; ++index)
|
||||
{
|
||||
AddFileDescriptorToList(i);
|
||||
var fileDescriptor = fileDescriptors[i];
|
||||
var fullFilePath = "{0}\\{1}\\{2}".F(fileGroup.Name, DirectoryName(fileDescriptor.DirectoryIndex), fileDescriptor.Filename);
|
||||
index.Add(fullFilePath, i);
|
||||
AddFileDescriptorToList(index);
|
||||
var fileDescriptor = fileDescriptors[index];
|
||||
var fullFilePath = "{0}\\{1}\\{2}".F(fileGroup.Name, DirectoryName((uint)fileDescriptor.DirectoryIndex), fileDescriptor.Filename);
|
||||
fileLookup.Add(fullFilePath, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -405,9 +404,9 @@ namespace OpenRA.FileSystem
|
||||
return test;
|
||||
}
|
||||
|
||||
public bool Contains(string filename)
|
||||
public bool Exists(string filename)
|
||||
{
|
||||
return index.ContainsKey(filename);
|
||||
return fileLookup.ContainsKey(filename);
|
||||
}
|
||||
|
||||
public uint DirectoryCount()
|
||||
@@ -449,6 +448,16 @@ namespace OpenRA.FileSystem
|
||||
GetContentById(index, destfile);
|
||||
}
|
||||
|
||||
public void Write(Dictionary<string, byte[]> input)
|
||||
{
|
||||
throw new NotImplementedException("Cannot Add Files To Cab");
|
||||
}
|
||||
|
||||
public IEnumerable<uint> ClassicHashes()
|
||||
{
|
||||
return fileLookup.Keys.Select(k => PackageEntry.HashFilename(k, PackageHashType.Classic));
|
||||
}
|
||||
|
||||
public Stream GetContentById(uint index)
|
||||
{
|
||||
var fileDes = fileDescriptors[index];
|
||||
@@ -459,11 +468,11 @@ namespace OpenRA.FileSystem
|
||||
return GetContentById(fileDes.LinkToPrevious);
|
||||
|
||||
if ((fileDes.Flags & FileObfuscated) != 0)
|
||||
throw new NotImplementedException("Haven't implemented obfuscated files");
|
||||
throw new NotImplementedException("Haven't implemented obfustcated files");
|
||||
|
||||
var output = new MemoryStream((int)fileDes.ExpandedSize);
|
||||
|
||||
using (var reader = new CabReader(context, fileDes, index, Name))
|
||||
using (var reader = new CabReader(fileDes, index, commonName))
|
||||
reader.CopyTo(output);
|
||||
|
||||
if (output.Length != fileDes.ExpandedSize)
|
||||
@@ -486,18 +495,28 @@ namespace OpenRA.FileSystem
|
||||
}
|
||||
|
||||
if ((fileDes.Flags & FileObfuscated) != 0)
|
||||
throw new NotImplementedException("Haven't implemented obfuscated files");
|
||||
throw new NotImplementedException("Haven't implemented obfustcated files");
|
||||
|
||||
using (var reader = new CabReader(context, fileDes, index, Name))
|
||||
using (var reader = new CabReader(fileDes, index, commonName))
|
||||
reader.CopyTo(output);
|
||||
|
||||
if (output.Length != fileDes.ExpandedSize)
|
||||
throw new Exception("Did not fully extract Expected = {0}, Got = {1}".F(fileDes.ExpandedSize, output.Length));
|
||||
}
|
||||
|
||||
public Stream GetStream(string fileName)
|
||||
public Stream GetContent(string fileName)
|
||||
{
|
||||
return GetContentById(index[fileName]);
|
||||
return GetContentById(fileLookup[fileName]);
|
||||
}
|
||||
|
||||
public IEnumerable<uint> CrcHashes()
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
public IEnumerable<string> AllFileNames()
|
||||
{
|
||||
return fileLookup.Keys;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
@@ -16,70 +15,54 @@ using OpenRA.FileFormats;
|
||||
|
||||
namespace OpenRA.FileSystem
|
||||
{
|
||||
public sealed class InstallShieldPackage : IReadOnlyPackage
|
||||
public sealed class InstallShieldPackage : IFolder
|
||||
{
|
||||
struct Entry
|
||||
{
|
||||
public readonly uint Offset;
|
||||
public readonly uint Length;
|
||||
|
||||
public Entry(uint offset, uint length)
|
||||
{
|
||||
Offset = offset;
|
||||
Length = length;
|
||||
}
|
||||
}
|
||||
|
||||
public string Name { get; private set; }
|
||||
public IEnumerable<string> Contents { get { return index.Keys; } }
|
||||
|
||||
readonly Dictionary<string, Entry> index = new Dictionary<string, Entry>();
|
||||
readonly Dictionary<uint, PackageEntry> index = new Dictionary<uint, PackageEntry>();
|
||||
readonly List<string> filenames;
|
||||
readonly Stream s;
|
||||
readonly long dataStart = 255;
|
||||
readonly int priority;
|
||||
readonly string filename;
|
||||
|
||||
public InstallShieldPackage(FileSystem context, string filename)
|
||||
public InstallShieldPackage(string filename, int priority)
|
||||
{
|
||||
Name = filename;
|
||||
this.filename = filename;
|
||||
this.priority = priority;
|
||||
|
||||
s = context.Open(filename);
|
||||
filenames = new List<string>();
|
||||
|
||||
s = GlobalFileSystem.Open(filename);
|
||||
try
|
||||
{
|
||||
// Parse package header
|
||||
var signature = s.ReadUInt32();
|
||||
var reader = new BinaryReader(s);
|
||||
var signature = reader.ReadUInt32();
|
||||
if (signature != 0x8C655D13)
|
||||
throw new InvalidDataException("Not an Installshield package");
|
||||
|
||||
s.Position += 8;
|
||||
/*var FileCount = */s.ReadUInt16();
|
||||
s.Position += 4;
|
||||
/*var ArchiveSize = */s.ReadUInt32();
|
||||
s.Position += 19;
|
||||
var tocAddress = s.ReadInt32();
|
||||
s.Position += 4;
|
||||
var dirCount = s.ReadUInt16();
|
||||
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.Position = tocAddress;
|
||||
s.Seek(tocAddress, SeekOrigin.Begin);
|
||||
var tocReader = new BinaryReader(s);
|
||||
|
||||
var fileCountInDirs = new List<uint>();
|
||||
|
||||
// Parse directories
|
||||
var directories = new Dictionary<string, uint>();
|
||||
for (var i = 0; i < dirCount; i++)
|
||||
{
|
||||
// Parse directory header
|
||||
var fileCount = s.ReadUInt16();
|
||||
var chunkSize = s.ReadUInt16();
|
||||
var nameLength = s.ReadUInt16();
|
||||
var dirName = s.ReadASCII(nameLength);
|
||||
|
||||
// Skip to the end of the chunk
|
||||
s.ReadBytes(chunkSize - nameLength - 6);
|
||||
directories.Add(dirName, fileCount);
|
||||
}
|
||||
fileCountInDirs.Add(ParseDirectory(tocReader));
|
||||
|
||||
// Parse files
|
||||
foreach (var dir in directories)
|
||||
for (var i = 0; i < dir.Value; i++)
|
||||
ParseFile(s, dir.Key);
|
||||
foreach (var fileCount in fileCountInDirs)
|
||||
for (var i = 0; i < fileCount; i++)
|
||||
ParseFile(reader);
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -88,29 +71,44 @@ namespace OpenRA.FileSystem
|
||||
}
|
||||
}
|
||||
|
||||
uint accumulatedData = 0;
|
||||
void ParseFile(Stream s, string dirName)
|
||||
static uint ParseDirectory(BinaryReader reader)
|
||||
{
|
||||
s.Position += 7;
|
||||
var compressedSize = s.ReadUInt32();
|
||||
s.Position += 12;
|
||||
var chunkSize = s.ReadUInt16();
|
||||
s.Position += 4;
|
||||
var nameLength = s.ReadByte();
|
||||
var fileName = dirName + "\\" + s.ReadASCII(nameLength);
|
||||
// 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));
|
||||
|
||||
// Use index syntax to overwrite any duplicate entries with the last value
|
||||
index[fileName] = new Entry(accumulatedData, compressedSize);
|
||||
// Skip to the end of the chunk
|
||||
reader.ReadBytes(chunkSize - nameLength - 6);
|
||||
return fileCount;
|
||||
}
|
||||
|
||||
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, PackageHashType.Classic);
|
||||
if (!index.ContainsKey(hash))
|
||||
index.Add(hash, new PackageEntry(hash, accumulatedData, compressedSize));
|
||||
filenames.Add(fileName);
|
||||
accumulatedData += compressedSize;
|
||||
|
||||
// Skip to the end of the chunk
|
||||
s.Position += chunkSize - nameLength - 30;
|
||||
reader.ReadBytes(chunkSize - nameLength - 30);
|
||||
}
|
||||
|
||||
public Stream GetStream(string filename)
|
||||
public Stream GetContent(uint hash)
|
||||
{
|
||||
Entry e;
|
||||
if (!index.TryGetValue(filename, out e))
|
||||
PackageEntry e;
|
||||
if (!index.TryGetValue(hash, out e))
|
||||
return null;
|
||||
|
||||
s.Seek(dataStart + e.Offset, SeekOrigin.Begin);
|
||||
@@ -119,9 +117,37 @@ namespace OpenRA.FileSystem
|
||||
return new MemoryStream(Blast.Decompress(data));
|
||||
}
|
||||
|
||||
public bool Contains(string filename)
|
||||
public Stream GetContent(string filename)
|
||||
{
|
||||
return index.ContainsKey(filename);
|
||||
return GetContent(PackageEntry.HashFilename(filename, PackageHashType.Classic));
|
||||
}
|
||||
|
||||
public IEnumerable<uint> ClassicHashes()
|
||||
{
|
||||
return index.Keys;
|
||||
}
|
||||
|
||||
public IEnumerable<uint> CrcHashes()
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
public IEnumerable<string> AllFileNames()
|
||||
{
|
||||
return filenames;
|
||||
}
|
||||
|
||||
public bool Exists(string filename)
|
||||
{
|
||||
return index.ContainsKey(PackageEntry.HashFilename(filename, PackageHashType.Classic));
|
||||
}
|
||||
|
||||
public int Priority { get { return 2000 + priority; } }
|
||||
public string Name { get { return filename; } }
|
||||
|
||||
public void Write(Dictionary<string, byte[]> contents)
|
||||
{
|
||||
throw new NotImplementedException("Cannot save InstallShieldPackages.");
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
@@ -15,26 +14,49 @@ using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Primitives;
|
||||
|
||||
namespace OpenRA.FileSystem
|
||||
{
|
||||
public sealed class MixFile : IReadOnlyPackage
|
||||
public sealed class MixFile : IFolder
|
||||
{
|
||||
public string Name { get; private set; }
|
||||
public IEnumerable<string> Contents { get { return index.Keys; } }
|
||||
|
||||
readonly Dictionary<string, PackageEntry> index;
|
||||
readonly Dictionary<uint, PackageEntry> index;
|
||||
readonly long dataStart;
|
||||
readonly Stream s;
|
||||
readonly FileSystem context;
|
||||
readonly int priority;
|
||||
readonly string filename;
|
||||
readonly PackageHashType type;
|
||||
|
||||
public MixFile(FileSystem context, string filename)
|
||||
// Save a mix to disk with the given contents
|
||||
public MixFile(string filename, int priority, Dictionary<string, byte[]> contents)
|
||||
{
|
||||
Name = filename;
|
||||
this.context = context;
|
||||
this.filename = filename;
|
||||
this.priority = priority;
|
||||
this.type = PackageHashType.Classic;
|
||||
|
||||
s = context.Open(filename);
|
||||
if (File.Exists(filename))
|
||||
File.Delete(filename);
|
||||
|
||||
s = File.Create(filename);
|
||||
try
|
||||
{
|
||||
index = new Dictionary<uint, PackageEntry>();
|
||||
contents.Add("local mix database.dat", new XccLocalDatabase(contents.Keys.Append("local mix database.dat")).Data());
|
||||
Write(contents);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Dispose();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public MixFile(string filename, PackageHashType type, int priority)
|
||||
{
|
||||
this.filename = filename;
|
||||
this.priority = priority;
|
||||
this.type = type;
|
||||
|
||||
s = GlobalFileSystem.Open(filename);
|
||||
try
|
||||
{
|
||||
// Detect format type
|
||||
@@ -54,9 +76,9 @@ namespace OpenRA.FileSystem
|
||||
else
|
||||
entries = ParseHeader(s, isCncMix ? 0 : 4, out dataStart);
|
||||
|
||||
index = ParseIndex(entries.ToDictionaryWithConflictLog(x => x.Hash,
|
||||
index = entries.ToDictionaryWithConflictLog(x => x.Hash,
|
||||
"{0} ({1} format, Encrypted: {2}, DataStart: {3})".F(filename, isCncMix ? "C&C" : "RA/TS/RA2", isEncrypted, dataStart),
|
||||
null, x => "(offs={0}, len={1})".F(x.Offset, x.Length)));
|
||||
null, x => "(offs={0}, len={1})".F(x.Offset, x.Length));
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
@@ -65,58 +87,6 @@ namespace OpenRA.FileSystem
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary<string, PackageEntry> ParseIndex(Dictionary<uint, PackageEntry> entries)
|
||||
{
|
||||
var classicIndex = new Dictionary<string, PackageEntry>();
|
||||
var crcIndex = new Dictionary<string, PackageEntry>();
|
||||
var allPossibleFilenames = new HashSet<string>();
|
||||
|
||||
// Try and find a local mix database
|
||||
var dbNameClassic = PackageEntry.HashFilename("local mix database.dat", PackageHashType.Classic);
|
||||
var dbNameCRC = PackageEntry.HashFilename("local mix database.dat", PackageHashType.CRC32);
|
||||
foreach (var kv in entries)
|
||||
{
|
||||
if (kv.Key == dbNameClassic || kv.Key == dbNameCRC)
|
||||
{
|
||||
var db = new XccLocalDatabase(GetContent(kv.Value));
|
||||
foreach (var e in db.Entries)
|
||||
allPossibleFilenames.Add(e);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Load the global mix database
|
||||
// TODO: This should be passed to the mix file ctor
|
||||
if (context.Exists("global mix database.dat"))
|
||||
{
|
||||
var db = new XccGlobalDatabase(context.Open("global mix database.dat"));
|
||||
foreach (var e in db.Entries)
|
||||
allPossibleFilenames.Add(e);
|
||||
}
|
||||
|
||||
foreach (var filename in allPossibleFilenames)
|
||||
{
|
||||
var classicHash = PackageEntry.HashFilename(filename, PackageHashType.Classic);
|
||||
var crcHash = PackageEntry.HashFilename(filename, PackageHashType.CRC32);
|
||||
PackageEntry e;
|
||||
|
||||
if (entries.TryGetValue(classicHash, out e))
|
||||
classicIndex.Add(filename, e);
|
||||
|
||||
if (entries.TryGetValue(crcHash, out e))
|
||||
crcIndex.Add(filename, e);
|
||||
}
|
||||
|
||||
var bestIndex = crcIndex.Count > classicIndex.Count ? crcIndex : classicIndex;
|
||||
|
||||
var unknown = entries.Count - bestIndex.Count;
|
||||
if (unknown > 0)
|
||||
Log.Write("debug", "{0}: failed to resolve filenames for {1} unknown hashes".F(Name, unknown));
|
||||
|
||||
return bestIndex;
|
||||
}
|
||||
|
||||
static List<PackageEntry> ParseHeader(Stream s, long offset, out long headerEnd)
|
||||
{
|
||||
s.Seek(offset, SeekOrigin.Begin);
|
||||
@@ -186,26 +156,130 @@ namespace OpenRA.FileSystem
|
||||
return ret;
|
||||
}
|
||||
|
||||
public Stream GetContent(PackageEntry entry)
|
||||
uint? FindMatchingHash(string filename)
|
||||
{
|
||||
Stream parentStream;
|
||||
var offset = dataStart + entry.Offset + SegmentStream.GetOverallNestedOffset(s, out parentStream);
|
||||
var path = ((FileStream)parentStream).Name;
|
||||
return new SegmentStream(File.OpenRead(path), offset, entry.Length);
|
||||
}
|
||||
var hash = PackageEntry.HashFilename(filename, type);
|
||||
if (index.ContainsKey(hash))
|
||||
return hash;
|
||||
|
||||
public Stream GetStream(string filename)
|
||||
{
|
||||
PackageEntry e;
|
||||
if (!index.TryGetValue(filename, out e))
|
||||
// Maybe we were given a raw hash?
|
||||
uint raw;
|
||||
if (!uint.TryParse(filename, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out raw))
|
||||
return null;
|
||||
|
||||
return GetContent(e);
|
||||
if ("{0:X}".F(raw) == filename && index.ContainsKey(raw))
|
||||
return raw;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool Contains(string filename)
|
||||
public Stream GetContent(uint hash)
|
||||
{
|
||||
return index.ContainsKey(filename);
|
||||
PackageEntry e;
|
||||
if (!index.TryGetValue(hash, out e))
|
||||
return null;
|
||||
|
||||
s.Seek(dataStart + e.Offset, SeekOrigin.Begin);
|
||||
var data = s.ReadBytes((int)e.Length);
|
||||
return new MemoryStream(data);
|
||||
}
|
||||
|
||||
public Stream GetContent(string filename)
|
||||
{
|
||||
var hash = FindMatchingHash(filename);
|
||||
return hash.HasValue ? GetContent(hash.Value) : null;
|
||||
}
|
||||
|
||||
static readonly uint[] Nothing = { };
|
||||
public IEnumerable<uint> ClassicHashes()
|
||||
{
|
||||
if (type == PackageHashType.Classic)
|
||||
return index.Keys;
|
||||
|
||||
return Nothing;
|
||||
}
|
||||
|
||||
public IEnumerable<uint> CrcHashes()
|
||||
{
|
||||
if (type == PackageHashType.CRC32)
|
||||
return index.Keys;
|
||||
|
||||
return Nothing;
|
||||
}
|
||||
|
||||
public IEnumerable<string> AllFileNames()
|
||||
{
|
||||
var lookup = new Dictionary<uint, string>();
|
||||
if (Exists("local mix database.dat"))
|
||||
{
|
||||
var db = new XccLocalDatabase(GetContent("local mix database.dat"));
|
||||
foreach (var e in db.Entries)
|
||||
{
|
||||
var hash = PackageEntry.HashFilename(e, type);
|
||||
if (!lookup.ContainsKey(hash))
|
||||
lookup.Add(hash, e);
|
||||
}
|
||||
}
|
||||
|
||||
if (GlobalFileSystem.Exists("global mix database.dat"))
|
||||
{
|
||||
var db = new XccGlobalDatabase(GlobalFileSystem.Open("global mix database.dat"));
|
||||
foreach (var e in db.Entries)
|
||||
{
|
||||
var hash = PackageEntry.HashFilename(e, type);
|
||||
if (!lookup.ContainsKey(hash))
|
||||
lookup.Add(hash, e);
|
||||
}
|
||||
}
|
||||
|
||||
return index.Keys.Select(k => lookup.ContainsKey(k) ? lookup[k] : "{0:X}".F(k));
|
||||
}
|
||||
|
||||
public bool Exists(string filename)
|
||||
{
|
||||
return FindMatchingHash(filename).HasValue;
|
||||
}
|
||||
|
||||
public int Priority { get { return 1000 + priority; } }
|
||||
public string Name { get { return filename; } }
|
||||
|
||||
public void Write(Dictionary<string, byte[]> contents)
|
||||
{
|
||||
// Cannot modify existing mixfile - rename existing file and
|
||||
// create a new one with original content plus modifications
|
||||
GlobalFileSystem.Unmount(this);
|
||||
|
||||
// TODO: Add existing data to the contents list
|
||||
if (index.Count > 0)
|
||||
throw new NotImplementedException("Updating mix files unfinished");
|
||||
|
||||
// Construct a list of entries for the file header
|
||||
uint dataSize = 0;
|
||||
var items = new List<PackageEntry>();
|
||||
foreach (var kv in contents)
|
||||
{
|
||||
var length = (uint)kv.Value.Length;
|
||||
var hash = PackageEntry.HashFilename(Path.GetFileName(kv.Key), type);
|
||||
items.Add(new PackageEntry(hash, dataSize, length));
|
||||
dataSize += length;
|
||||
}
|
||||
|
||||
// Write the new file
|
||||
s.Seek(0, SeekOrigin.Begin);
|
||||
using (var writer = new BinaryWriter(s))
|
||||
{
|
||||
// Write file header
|
||||
writer.Write((ushort)items.Count);
|
||||
writer.Write(dataSize);
|
||||
foreach (var item in items)
|
||||
item.Write(writer);
|
||||
|
||||
writer.Flush();
|
||||
|
||||
// Copy file data
|
||||
foreach (var file in contents)
|
||||
s.Write(file.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
@@ -21,20 +21,20 @@ namespace OpenRA.FileSystem
|
||||
public string Filename;
|
||||
}
|
||||
|
||||
public sealed class PakFile : IReadOnlyPackage
|
||||
public sealed class PakFile : IFolder
|
||||
{
|
||||
public string Name { get; private set; }
|
||||
public IEnumerable<string> Contents { get { return index.Keys; } }
|
||||
|
||||
readonly string filename;
|
||||
readonly int priority;
|
||||
readonly Dictionary<string, Entry> index;
|
||||
readonly Stream stream;
|
||||
|
||||
public PakFile(FileSystem context, string filename)
|
||||
public PakFile(string filename, int priority)
|
||||
{
|
||||
Name = filename;
|
||||
this.filename = filename;
|
||||
this.priority = priority;
|
||||
index = new Dictionary<string, Entry>();
|
||||
|
||||
stream = context.Open(filename);
|
||||
stream = GlobalFileSystem.Open(filename);
|
||||
try
|
||||
{
|
||||
index = new Dictionary<string, Entry>();
|
||||
@@ -60,7 +60,7 @@ namespace OpenRA.FileSystem
|
||||
}
|
||||
}
|
||||
|
||||
public Stream GetStream(string filename)
|
||||
public Stream GetContent(string filename)
|
||||
{
|
||||
Entry entry;
|
||||
if (!index.TryGetValue(filename, out entry))
|
||||
@@ -71,11 +71,36 @@ namespace OpenRA.FileSystem
|
||||
return new MemoryStream(data);
|
||||
}
|
||||
|
||||
public bool Contains(string filename)
|
||||
public IEnumerable<uint> ClassicHashes()
|
||||
{
|
||||
foreach (var filename in index.Keys)
|
||||
yield return PackageEntry.HashFilename(filename, PackageHashType.Classic);
|
||||
}
|
||||
|
||||
public IEnumerable<uint> CrcHashes()
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
public IEnumerable<string> AllFileNames()
|
||||
{
|
||||
foreach (var filename in index.Keys)
|
||||
yield return filename;
|
||||
}
|
||||
|
||||
public bool Exists(string filename)
|
||||
{
|
||||
return index.ContainsKey(filename);
|
||||
}
|
||||
|
||||
public void Write(Dictionary<string, byte[]> contents)
|
||||
{
|
||||
throw new NotImplementedException("Cannot save Pak archives.");
|
||||
}
|
||||
|
||||
public int Priority { get { return 1000 + priority; } }
|
||||
public string Name { get { return filename; } }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
stream.Dispose();
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
@@ -17,37 +17,46 @@ using SZipFile = ICSharpCode.SharpZipLib.Zip.ZipFile;
|
||||
|
||||
namespace OpenRA.FileSystem
|
||||
{
|
||||
public sealed class ZipFile : IReadWritePackage
|
||||
public sealed class ZipFile : IFolder
|
||||
{
|
||||
public string Name { get; private set; }
|
||||
readonly string filename;
|
||||
readonly int priority;
|
||||
SZipFile pkg;
|
||||
|
||||
static ZipFile()
|
||||
{
|
||||
ZipConstants.DefaultCodePage = Encoding.UTF8.CodePage;
|
||||
ZipConstants.DefaultCodePage = Encoding.Default.CodePage;
|
||||
}
|
||||
|
||||
public ZipFile(FileSystem context, string filename, Stream stream, bool createOrClearContents = false)
|
||||
public ZipFile(string filename, int priority)
|
||||
{
|
||||
Name = filename;
|
||||
|
||||
if (createOrClearContents)
|
||||
pkg = SZipFile.Create(stream);
|
||||
else
|
||||
pkg = new SZipFile(stream);
|
||||
this.filename = filename;
|
||||
this.priority = priority;
|
||||
try
|
||||
{
|
||||
// pull the file into memory, dont keep it open.
|
||||
pkg = new SZipFile(new MemoryStream(File.ReadAllBytes(filename)));
|
||||
}
|
||||
catch (ZipException e)
|
||||
{
|
||||
Log.Write("debug", "Couldn't load zip file: {0}", e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public ZipFile(IReadOnlyFileSystem context, string filename, bool createOrClearContents = false)
|
||||
// Create a new zip with the specified contents
|
||||
public ZipFile(string filename, int priority, Dictionary<string, byte[]> contents)
|
||||
{
|
||||
Name = filename;
|
||||
this.priority = priority;
|
||||
this.filename = filename;
|
||||
|
||||
if (createOrClearContents)
|
||||
pkg = SZipFile.Create(filename);
|
||||
else
|
||||
pkg = new SZipFile(filename);
|
||||
if (File.Exists(filename))
|
||||
File.Delete(filename);
|
||||
|
||||
pkg = SZipFile.Create(filename);
|
||||
Write(contents);
|
||||
}
|
||||
|
||||
public Stream GetStream(string filename)
|
||||
public Stream GetContent(string filename)
|
||||
{
|
||||
var entry = pkg.GetEntry(filename);
|
||||
if (entry == null)
|
||||
@@ -62,32 +71,44 @@ namespace OpenRA.FileSystem
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<string> Contents
|
||||
public IEnumerable<uint> ClassicHashes()
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (ZipEntry entry in pkg)
|
||||
yield return entry.Name;
|
||||
}
|
||||
foreach (ZipEntry entry in pkg)
|
||||
yield return PackageEntry.HashFilename(entry.Name, PackageHashType.Classic);
|
||||
}
|
||||
|
||||
public bool Contains(string filename)
|
||||
public IEnumerable<uint> CrcHashes()
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
public IEnumerable<string> AllFileNames()
|
||||
{
|
||||
foreach (ZipEntry entry in pkg)
|
||||
yield return entry.Name;
|
||||
}
|
||||
|
||||
public bool Exists(string filename)
|
||||
{
|
||||
return pkg.GetEntry(filename) != null;
|
||||
}
|
||||
|
||||
public void Update(string filename, byte[] contents)
|
||||
{
|
||||
pkg.BeginUpdate();
|
||||
pkg.Add(new StaticMemoryDataSource(contents), filename);
|
||||
pkg.CommitUpdate();
|
||||
}
|
||||
public int Priority { get { return 500 + priority; } }
|
||||
public string Name { get { return filename; } }
|
||||
|
||||
public void Delete(string filename)
|
||||
public void Write(Dictionary<string, byte[]> contents)
|
||||
{
|
||||
// TODO: Clear existing content?
|
||||
pkg.Close();
|
||||
pkg = SZipFile.Create(filename);
|
||||
pkg.BeginUpdate();
|
||||
pkg.Delete(filename);
|
||||
|
||||
foreach (var kvp in contents)
|
||||
pkg.Add(new StaticMemoryDataSource(kvp.Value), kvp.Key);
|
||||
|
||||
pkg.CommitUpdate();
|
||||
pkg.Close();
|
||||
pkg = new SZipFile(new MemoryStream(File.ReadAllBytes(filename)));
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2015 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 COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using ICSharpCode.SharpZipLib.Zip;
|
||||
using SZipFile = ICSharpCode.SharpZipLib.Zip.ZipFile;
|
||||
|
||||
namespace OpenRA.FileSystem
|
||||
{
|
||||
public sealed class ZipFolder : IReadOnlyPackage
|
||||
{
|
||||
public string Name { get; private set; }
|
||||
public ZipFile Parent { get; private set; }
|
||||
readonly string path;
|
||||
|
||||
static ZipFolder()
|
||||
{
|
||||
ZipConstants.DefaultCodePage = Encoding.UTF8.CodePage;
|
||||
}
|
||||
|
||||
public ZipFolder(FileSystem context, ZipFile parent, string path, string filename)
|
||||
{
|
||||
if (filename.EndsWith("/"))
|
||||
filename = filename.Substring(0, filename.Length - 1);
|
||||
|
||||
Name = filename;
|
||||
Parent = parent;
|
||||
if (path.EndsWith("/"))
|
||||
path = path.Substring(0, path.Length - 1);
|
||||
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public Stream GetStream(string filename)
|
||||
{
|
||||
// Zip files use '/' as a path separator
|
||||
return Parent.GetStream(path + '/' + filename);
|
||||
}
|
||||
|
||||
public IEnumerable<string> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (var entry in Parent.Contents)
|
||||
{
|
||||
if (entry.StartsWith(path) && entry != path)
|
||||
{
|
||||
var filename = entry.Substring(path.Length + 1);
|
||||
var dirLevels = filename.Split('/').Count(c => !string.IsNullOrEmpty(c));
|
||||
if (dirLevels == 1)
|
||||
yield return filename;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Contains(string filename)
|
||||
{
|
||||
return Parent.Contains(path + '/' + filename);
|
||||
}
|
||||
|
||||
public void Dispose() { /* nothing to do */ }
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,14 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
@@ -19,6 +17,7 @@ using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using OpenRA.Chat;
|
||||
using OpenRA.FileSystem;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Network;
|
||||
using OpenRA.Primitives;
|
||||
@@ -47,15 +46,13 @@ namespace OpenRA
|
||||
public static Sound Sound;
|
||||
public static bool HasInputFocus = false;
|
||||
|
||||
public static bool BenchmarkMode = false;
|
||||
|
||||
public static GlobalChat GlobalChat;
|
||||
|
||||
public static OrderManager JoinServer(string host, int port, string password, bool recordReplay = true)
|
||||
{
|
||||
var connection = new NetworkConnection(host, port);
|
||||
IConnection connection = new NetworkConnection(host, port);
|
||||
if (recordReplay)
|
||||
connection.StartRecording(TimestampedFilename);
|
||||
connection = new ReplayRecorderConnection(connection, TimestampedFilename);
|
||||
|
||||
var om = new OrderManager(host, port, password, connection);
|
||||
JoinInner(om);
|
||||
@@ -87,7 +84,7 @@ namespace OpenRA
|
||||
|
||||
// More accurate replacement for Environment.TickCount
|
||||
static Stopwatch stopwatch = Stopwatch.StartNew();
|
||||
public static int RunTime { get { return (int)stopwatch.ElapsedMilliseconds; } }
|
||||
public static int RunTime { get { return (int)Game.stopwatch.ElapsedMilliseconds; } }
|
||||
|
||||
public static int RenderFrame = 0;
|
||||
public static int NetFrameNumber { get { return OrderManager.NetFrameNumber; } }
|
||||
@@ -176,46 +173,6 @@ namespace OpenRA
|
||||
GC.Collect();
|
||||
}
|
||||
|
||||
public static void RestartGame()
|
||||
{
|
||||
var replay = OrderManager.Connection as ReplayConnection;
|
||||
var replayName = replay != null ? replay.Filename : null;
|
||||
var lobbyInfo = OrderManager.LobbyInfo;
|
||||
var orders = new[] {
|
||||
Order.Command("sync_lobby {0}".F(lobbyInfo.Serialize())),
|
||||
Order.Command("startgame")
|
||||
};
|
||||
|
||||
// Disconnect from the current game
|
||||
Disconnect();
|
||||
Ui.ResetAll();
|
||||
|
||||
// Restart the game with the same replay/mission
|
||||
if (replay != null)
|
||||
JoinReplay(replayName);
|
||||
else
|
||||
CreateAndStartLocalServer(lobbyInfo.GlobalSettings.Map, orders);
|
||||
}
|
||||
|
||||
public static void CreateAndStartLocalServer(string mapUID, IEnumerable<Order> setupOrders, Action onStart = null)
|
||||
{
|
||||
OrderManager om = null;
|
||||
|
||||
Action lobbyReady = null;
|
||||
lobbyReady = () =>
|
||||
{
|
||||
LobbyInfoChanged -= lobbyReady;
|
||||
foreach (var o in setupOrders)
|
||||
om.IssueOrder(o);
|
||||
|
||||
if (onStart != null)
|
||||
onStart();
|
||||
};
|
||||
LobbyInfoChanged += lobbyReady;
|
||||
|
||||
om = JoinServer(IPAddress.Loopback.ToString(), CreateLocalServer(mapUID), "");
|
||||
}
|
||||
|
||||
public static bool IsHost
|
||||
{
|
||||
get
|
||||
@@ -232,13 +189,15 @@ namespace OpenRA
|
||||
|
||||
public static void InitializeSettings(Arguments args)
|
||||
{
|
||||
Settings = new Settings(Platform.ResolvePath(Path.Combine("^", "settings.yaml")), args);
|
||||
Settings = new Settings(Platform.ResolvePath("^", "settings.yaml"), args);
|
||||
}
|
||||
|
||||
internal static void Initialize(Arguments args)
|
||||
{
|
||||
Console.WriteLine("Platform is {0}", Platform.CurrentPlatform);
|
||||
|
||||
AppDomain.CurrentDomain.AssemblyResolve += GlobalFileSystem.ResolveAssembly;
|
||||
|
||||
InitializeSettings(args);
|
||||
|
||||
Log.AddChannel("perf", "perf.log");
|
||||
@@ -260,6 +219,7 @@ namespace OpenRA
|
||||
|
||||
GeoIP.Initialize();
|
||||
|
||||
GlobalFileSystem.Mount(Platform.GameDir); // Needed to access shaders
|
||||
var renderers = new[] { Settings.Graphics.Renderer, "Default", null };
|
||||
foreach (var r in renderers)
|
||||
{
|
||||
@@ -279,7 +239,7 @@ namespace OpenRA
|
||||
}
|
||||
}
|
||||
|
||||
Sound = new Sound(Settings.Sound.Engine);
|
||||
Sound = new Sound(Settings.Server.Dedicated ? "Null" : Settings.Sound.Engine);
|
||||
|
||||
GlobalChat = new GlobalChat();
|
||||
|
||||
@@ -293,18 +253,6 @@ namespace OpenRA
|
||||
RunAfterDelay(Settings.Server.NatDiscoveryTimeout, UPnP.StoppingNatDiscovery);
|
||||
}
|
||||
|
||||
public static bool IsModInstalled(string modId)
|
||||
{
|
||||
return ModMetadata.AllMods[modId].RequiresMods.All(IsModInstalled);
|
||||
}
|
||||
|
||||
public static bool IsModInstalled(KeyValuePair<string, string> mod)
|
||||
{
|
||||
return ModMetadata.AllMods.ContainsKey(mod.Key)
|
||||
&& ModMetadata.AllMods[mod.Key].Version == mod.Value
|
||||
&& IsModInstalled(mod.Key);
|
||||
}
|
||||
|
||||
public static void InitializeMod(string mod, Arguments args)
|
||||
{
|
||||
// Clear static state if we have switched mods
|
||||
@@ -325,27 +273,30 @@ namespace OpenRA
|
||||
OrderManager.Dispose();
|
||||
|
||||
if (ModData != null)
|
||||
{
|
||||
ModData.ModFiles.UnmountAll();
|
||||
ModData.Dispose();
|
||||
}
|
||||
|
||||
ModData = null;
|
||||
|
||||
// Fall back to default if the mod doesn't exist or has missing prerequisites.
|
||||
if (!ModMetadata.AllMods.ContainsKey(mod) || !IsModInstalled(mod))
|
||||
// Fall back to default if the mod doesn't exist
|
||||
if (!ModMetadata.AllMods.ContainsKey(mod))
|
||||
mod = new GameSettings().Mod;
|
||||
|
||||
Console.WriteLine("Loading mod: {0}", mod);
|
||||
Settings.Game.Mod = mod;
|
||||
|
||||
Sound.StopVideo();
|
||||
Sound.Initialize();
|
||||
|
||||
ModData = new ModData(mod, true);
|
||||
ModData = new ModData(mod, !Settings.Server.Dedicated);
|
||||
|
||||
using (new PerfTimer("LoadMaps"))
|
||||
ModData.MapCache.LoadMaps();
|
||||
|
||||
if (Settings.Server.Dedicated)
|
||||
{
|
||||
RunDedicatedServer();
|
||||
Environment.Exit(0);
|
||||
}
|
||||
|
||||
var installData = ModData.Manifest.Get<ContentInstaller>();
|
||||
var isModContentInstalled = installData.TestFiles.All(f => File.Exists(Platform.ResolvePath(f)));
|
||||
|
||||
@@ -356,8 +307,9 @@ namespace OpenRA
|
||||
return;
|
||||
}
|
||||
|
||||
ModData.InitializeLoaders(ModData.DefaultFileSystem);
|
||||
Renderer.InitializeFonts(ModData);
|
||||
ModData.MountFiles();
|
||||
ModData.InitializeLoaders();
|
||||
Renderer.InitializeFonts(ModData.Manifest);
|
||||
|
||||
if (Cursor != null)
|
||||
Cursor.Dispose();
|
||||
@@ -392,6 +344,37 @@ namespace OpenRA
|
||||
ModData.LoadScreen.StartGame(args);
|
||||
}
|
||||
|
||||
public static void RunDedicatedServer()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
Settings.Server.Map = WidgetUtils.ChooseInitialMap(Settings.Server.Map);
|
||||
Settings.Save();
|
||||
CreateServer(new ServerSettings(Settings.Server));
|
||||
|
||||
while (true)
|
||||
{
|
||||
Thread.Sleep(100);
|
||||
|
||||
if (server.State == Server.ServerState.GameStarted && server.Conns.Count < 1)
|
||||
{
|
||||
Console.WriteLine("No one is playing, shutting down...");
|
||||
server.Shutdown();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Settings.Server.DedicatedLoop)
|
||||
{
|
||||
Console.WriteLine("Starting a new server instance...");
|
||||
ModData.MapCache.LoadMaps();
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static void LoadEditor(string mapUid)
|
||||
{
|
||||
StartGame(mapUid, WorldType.Editor);
|
||||
@@ -408,7 +391,7 @@ namespace OpenRA
|
||||
static string ChooseShellmap()
|
||||
{
|
||||
var shellmaps = ModData.MapCache
|
||||
.Where(m => m.Status == MapStatus.Available && m.Visibility.HasFlag(MapVisibility.Shellmap))
|
||||
.Where(m => m.Status == MapStatus.Available && m.Map.Visibility.HasFlag(MapVisibility.Shellmap))
|
||||
.Select(m => m.Uid);
|
||||
|
||||
if (!shellmaps.Any())
|
||||
@@ -421,10 +404,10 @@ namespace OpenRA
|
||||
public static event Action OnQuit = () => { };
|
||||
|
||||
// Note: These delayed actions should only be used by widgets or disposing objects
|
||||
// - things that depend on a particular world should be queuing them on the world actor.
|
||||
// - things that depend on a particular world should be queuing them on the worldactor.
|
||||
static volatile ActionQueue delayedActions = new ActionQueue();
|
||||
public static void RunAfterTick(Action a) { delayedActions.Add(a, RunTime); }
|
||||
public static void RunAfterDelay(int delayMilliseconds, Action a) { delayedActions.Add(a, RunTime + delayMilliseconds); }
|
||||
public static void RunAfterTick(Action a) { delayedActions.Add(a, Game.RunTime); }
|
||||
public static void RunAfterDelay(int delayMilliseconds, Action a) { delayedActions.Add(a, Game.RunTime + delayMilliseconds); }
|
||||
|
||||
static void TakeScreenshotInner()
|
||||
{
|
||||
@@ -451,7 +434,7 @@ namespace OpenRA
|
||||
|
||||
bitmap.Dispose();
|
||||
|
||||
RunAfterTick(() => Debug("Saved screenshot " + filename));
|
||||
Game.RunAfterTick(() => Debug("Saved screenshot " + filename));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -490,11 +473,7 @@ namespace OpenRA
|
||||
Sound.Tick();
|
||||
Sync.CheckSyncUnchanged(world, orderManager.TickImmediate);
|
||||
|
||||
if (world == null)
|
||||
return;
|
||||
|
||||
// Don't tick when the shellmap is disabled
|
||||
if (world.ShouldTick)
|
||||
if (world != null)
|
||||
{
|
||||
var isNetTick = LocalTick % NetTickScale == 0;
|
||||
|
||||
@@ -504,9 +483,6 @@ namespace OpenRA
|
||||
|
||||
Log.Write("debug", "--Tick: {0} ({1})", LocalTick, isNetTick ? "net" : "local");
|
||||
|
||||
if (BenchmarkMode)
|
||||
Log.Write("cpu", "{0};{1}".F(LocalTick, PerfHistory.Items["tick_time"].LastValue));
|
||||
|
||||
if (isNetTick)
|
||||
orderManager.Tick();
|
||||
|
||||
@@ -520,20 +496,19 @@ namespace OpenRA
|
||||
|
||||
PerfHistory.Tick();
|
||||
}
|
||||
else if (orderManager.NetFrameNumber == 0)
|
||||
orderManager.LastTickTime = RunTime;
|
||||
else
|
||||
if (orderManager.NetFrameNumber == 0)
|
||||
orderManager.LastTickTime = RunTime;
|
||||
|
||||
Sync.CheckSyncUnchanged(world, () => world.TickRender(worldRenderer));
|
||||
}
|
||||
else
|
||||
PerfHistory.Tick();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void LogicTick()
|
||||
{
|
||||
delayedActions.PerformActions(RunTime);
|
||||
delayedActions.PerformActions(Game.RunTime);
|
||||
|
||||
if (OrderManager.Connection.ConnectionState != lastConnectionState)
|
||||
{
|
||||
@@ -566,9 +541,9 @@ namespace OpenRA
|
||||
|
||||
using (new PerfSample("render_widgets"))
|
||||
{
|
||||
Renderer.WorldVoxelRenderer.BeginFrame();
|
||||
Game.Renderer.WorldVoxelRenderer.BeginFrame();
|
||||
Ui.PrepareRenderables();
|
||||
Renderer.WorldVoxelRenderer.EndFrame();
|
||||
Game.Renderer.WorldVoxelRenderer.EndFrame();
|
||||
|
||||
Ui.Draw();
|
||||
|
||||
@@ -593,9 +568,6 @@ namespace OpenRA
|
||||
PerfHistory.Items["batches"].Tick();
|
||||
PerfHistory.Items["render_widgets"].Tick();
|
||||
PerfHistory.Items["render_flip"].Tick();
|
||||
|
||||
if (BenchmarkMode)
|
||||
Log.Write("render", "{0};{1}".F(RenderFrame, PerfHistory.Items["render"].LastValue));
|
||||
}
|
||||
|
||||
static void Loop()
|
||||
@@ -646,7 +618,7 @@ namespace OpenRA
|
||||
{
|
||||
// Ideal time between logic updates. Timestep = 0 means the game is paused
|
||||
// but we still call LogicTick() because it handles pausing internally.
|
||||
var logicInterval = worldRenderer != null && worldRenderer.World.Timestep != 0 ? worldRenderer.World.Timestep : Timestep;
|
||||
var logicInterval = worldRenderer != null && worldRenderer.World.Timestep != 0 ? worldRenderer.World.Timestep : Game.Timestep;
|
||||
|
||||
// Ideal time between screen updates
|
||||
var maxFramerate = Settings.Graphics.CapFramerate ? Settings.Graphics.MaxFramerate.Clamp(1, 1000) : 1000;
|
||||
@@ -774,7 +746,7 @@ namespace OpenRA
|
||||
|
||||
public static void CreateServer(ServerSettings settings)
|
||||
{
|
||||
server = new Server.Server(new IPEndPoint(IPAddress.Any, settings.ListenPort), settings, ModData, false);
|
||||
server = new Server.Server(new IPEndPoint(IPAddress.Any, settings.ListenPort), settings, ModData);
|
||||
}
|
||||
|
||||
public static int CreateLocalServer(string map)
|
||||
@@ -787,7 +759,7 @@ namespace OpenRA
|
||||
AllowPortForward = false
|
||||
};
|
||||
|
||||
server = new Server.Server(new IPEndPoint(IPAddress.Loopback, 0), settings, ModData, false);
|
||||
server = new Server.Server(new IPEndPoint(IPAddress.Loopback, 0), settings, ModData);
|
||||
|
||||
return server.Port;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
@@ -26,30 +25,40 @@ namespace OpenRA
|
||||
/// The actor name can be anything, but the sprites used in the Render*: traits default to this one.
|
||||
/// If you add an ^ in front of the name, the engine will recognize this as a collection of traits
|
||||
/// that can be inherited by others (using Inherits:) and not a real unit.
|
||||
/// You can remove inherited traits by adding a - in front of them as in -TraitName: to inherit everything, but this trait.
|
||||
/// You can remove inherited traits by adding a - infront of them as in -TraitName: to inherit everything, but this trait.
|
||||
/// </summary>
|
||||
public readonly string Name;
|
||||
readonly TypeDictionary traits = new TypeDictionary();
|
||||
List<ITraitInfo> constructOrderCache = null;
|
||||
|
||||
public ActorInfo(ObjectCreator creator, string name, MiniYaml node)
|
||||
public ActorInfo(string name, MiniYaml node, Dictionary<string, MiniYaml> allUnits)
|
||||
{
|
||||
try
|
||||
{
|
||||
var allParents = new HashSet<string>();
|
||||
var abstractActorType = name.StartsWith("^");
|
||||
|
||||
// Guard against circular inheritance
|
||||
allParents.Add(name);
|
||||
var mergedNode = MergeWithParents(node, allUnits, allParents).ToDictionary();
|
||||
|
||||
Name = name;
|
||||
|
||||
var abstractActorType = name.StartsWith("^");
|
||||
foreach (var t in node.Nodes)
|
||||
foreach (var t in mergedNode)
|
||||
{
|
||||
try
|
||||
{
|
||||
traits.Add(LoadTraitInfo(creator, t.Key.Split('@')[0], t.Value));
|
||||
}
|
||||
catch (FieldLoader.MissingFieldsException e)
|
||||
{
|
||||
if (!abstractActorType)
|
||||
throw new YamlException(e.Message);
|
||||
}
|
||||
if (t.Key[0] == '-')
|
||||
throw new YamlException("Bogus trait removal: " + t.Key);
|
||||
|
||||
if (t.Key != "Inherits" && !t.Key.StartsWith("Inherits@"))
|
||||
try
|
||||
{
|
||||
traits.Add(LoadTraitInfo(t.Key.Split('@')[0], t.Value));
|
||||
}
|
||||
catch (FieldLoader.MissingFieldsException e)
|
||||
{
|
||||
if (!abstractActorType)
|
||||
throw new YamlException(e.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (YamlException e)
|
||||
@@ -65,12 +74,42 @@ namespace OpenRA
|
||||
traits.Add(t);
|
||||
}
|
||||
|
||||
static ITraitInfo LoadTraitInfo(ObjectCreator creator, string traitName, MiniYaml my)
|
||||
static Dictionary<string, MiniYaml> GetParents(MiniYaml node, Dictionary<string, MiniYaml> allUnits)
|
||||
{
|
||||
return node.Nodes.Where(n => n.Key == "Inherits" || n.Key.StartsWith("Inherits@"))
|
||||
.ToDictionary(n => n.Value.Value, n =>
|
||||
{
|
||||
MiniYaml i;
|
||||
if (!allUnits.TryGetValue(n.Value.Value, out i))
|
||||
throw new YamlException(
|
||||
"Bogus inheritance -- parent type {0} does not exist".F(n.Value.Value));
|
||||
|
||||
return i;
|
||||
});
|
||||
}
|
||||
|
||||
static MiniYaml MergeWithParents(MiniYaml node, Dictionary<string, MiniYaml> allUnits, HashSet<string> allParents)
|
||||
{
|
||||
var parents = GetParents(node, allUnits);
|
||||
|
||||
foreach (var kv in parents)
|
||||
{
|
||||
if (!allParents.Add(kv.Key))
|
||||
throw new YamlException(
|
||||
"Bogus inheritance -- duplicate inheritance of {0}.".F(kv.Key));
|
||||
|
||||
node = MiniYaml.MergeStrict(node, MergeWithParents(kv.Value, allUnits, allParents));
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static ITraitInfo LoadTraitInfo(string traitName, MiniYaml my)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(my.Value))
|
||||
throw new YamlException("Junk value `{0}` on trait node {1}"
|
||||
.F(my.Value, traitName));
|
||||
var info = creator.CreateObject<ITraitInfo>(traitName + "Info");
|
||||
var info = Game.CreateObject<ITraitInfo>(traitName + "Info");
|
||||
try
|
||||
{
|
||||
FieldLoader.Load(info, my);
|
||||
@@ -100,15 +139,9 @@ namespace OpenRA
|
||||
var unresolved = source.Except(resolved);
|
||||
|
||||
var testResolve = new Func<Type, Type, bool>((a, b) => a == b || a.IsAssignableFrom(b));
|
||||
var more = unresolved.Where(u => u.Dependencies.All(d => resolved.Exists(r => testResolve(d, r.Type))));
|
||||
|
||||
// This query detects which unresolved traits can be immediately resolved as all their direct dependencies are met.
|
||||
var more = unresolved.Where(u =>
|
||||
u.Dependencies.All(d => // To be resolvable, all dependencies must be satisfied according to the following conditions:
|
||||
resolved.Exists(r => testResolve(d, r.Type)) && // There must exist a resolved trait that meets the dependency.
|
||||
!unresolved.Any(u1 => testResolve(d, u1.Type)))); // All matching traits that meet this dependency must be resolved first.
|
||||
|
||||
// Continue resolving traits as long as possible.
|
||||
// Each time we resolve some traits, this means dependencies for other traits may then be possible to satisfy in the next pass.
|
||||
// Re-evaluate the vars above until sorted
|
||||
while (more.Any())
|
||||
resolved.AddRange(more);
|
||||
|
||||
@@ -128,14 +161,14 @@ namespace OpenRA
|
||||
exceptionString += u.Type + ": { " + string.Join(", ", deps) + " }\r\n";
|
||||
}
|
||||
|
||||
throw new YamlException(exceptionString);
|
||||
throw new Exception(exceptionString);
|
||||
}
|
||||
|
||||
constructOrderCache = resolved.Select(r => r.Trait).ToList();
|
||||
return constructOrderCache;
|
||||
}
|
||||
|
||||
public static IEnumerable<Type> PrerequisitesOf(ITraitInfo info)
|
||||
static IEnumerable<Type> PrerequisitesOf(ITraitInfo info)
|
||||
{
|
||||
return info
|
||||
.GetType()
|
||||
@@ -158,9 +191,9 @@ namespace OpenRA
|
||||
i.Name.Replace("Init", ""), i));
|
||||
}
|
||||
|
||||
public bool HasTraitInfo<T>() where T : ITraitInfoInterface { return traits.Contains<T>(); }
|
||||
public T TraitInfo<T>() where T : ITraitInfoInterface { return traits.Get<T>(); }
|
||||
public T TraitInfoOrDefault<T>() where T : ITraitInfoInterface { return traits.GetOrDefault<T>(); }
|
||||
public IEnumerable<T> TraitInfos<T>() where T : ITraitInfoInterface { return traits.WithInterface<T>(); }
|
||||
public bool HasTraitInfo<T>() where T : ITraitInfo { return traits.Contains<T>(); }
|
||||
public T TraitInfo<T>() where T : ITraitInfo { return traits.Get<T>(); }
|
||||
public T TraitInfoOrDefault<T>() where T : ITraitInfo { return traits.GetOrDefault<T>(); }
|
||||
public IEnumerable<T> TraitInfos<T>() where T : ITraitInfo { return traits.WithInterface<T>(); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.IO;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.FileSystem;
|
||||
|
||||
@@ -36,24 +34,19 @@ namespace OpenRA.GameRules
|
||||
Filename = (nd.ContainsKey("Filename") ? nd["Filename"].Value : key) + "." + ext;
|
||||
}
|
||||
|
||||
public void Load(IReadOnlyFileSystem fileSystem)
|
||||
public void Load()
|
||||
{
|
||||
Stream stream;
|
||||
if (!fileSystem.TryOpen(Filename, out stream))
|
||||
if (!GlobalFileSystem.Exists(Filename))
|
||||
return;
|
||||
|
||||
Exists = true;
|
||||
ISoundFormat soundFormat;
|
||||
foreach (var loader in Game.ModData.SoundLoaders)
|
||||
using (var s = GlobalFileSystem.Open(Filename))
|
||||
{
|
||||
if (loader.TryParseSound(stream, out soundFormat))
|
||||
{
|
||||
Length = (int)soundFormat.LengthInSeconds;
|
||||
break;
|
||||
}
|
||||
if (Filename.ToLowerInvariant().EndsWith("wav"))
|
||||
Length = (int)WavLoader.WaveLength(s);
|
||||
else
|
||||
Length = (int)AudLoader.SoundLength(s);
|
||||
}
|
||||
|
||||
stream.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using OpenRA.FileSystem;
|
||||
using OpenRA.GameRules;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Traits;
|
||||
@@ -27,25 +23,25 @@ namespace OpenRA
|
||||
public readonly IReadOnlyDictionary<string, SoundInfo> Voices;
|
||||
public readonly IReadOnlyDictionary<string, SoundInfo> Notifications;
|
||||
public readonly IReadOnlyDictionary<string, MusicInfo> Music;
|
||||
public readonly TileSet TileSet;
|
||||
public readonly SequenceProvider Sequences;
|
||||
public readonly IReadOnlyDictionary<string, TileSet> TileSets;
|
||||
public readonly IReadOnlyDictionary<string, SequenceProvider> Sequences;
|
||||
|
||||
public Ruleset(
|
||||
IReadOnlyDictionary<string, ActorInfo> actors,
|
||||
IReadOnlyDictionary<string, WeaponInfo> weapons,
|
||||
IReadOnlyDictionary<string, SoundInfo> voices,
|
||||
IReadOnlyDictionary<string, SoundInfo> notifications,
|
||||
IReadOnlyDictionary<string, MusicInfo> music,
|
||||
TileSet tileSet,
|
||||
SequenceProvider sequences)
|
||||
IDictionary<string, ActorInfo> actors,
|
||||
IDictionary<string, WeaponInfo> weapons,
|
||||
IDictionary<string, SoundInfo> voices,
|
||||
IDictionary<string, SoundInfo> notifications,
|
||||
IDictionary<string, MusicInfo> music,
|
||||
IDictionary<string, TileSet> tileSets,
|
||||
IDictionary<string, SequenceProvider> sequences)
|
||||
{
|
||||
Actors = actors;
|
||||
Weapons = weapons;
|
||||
Voices = voices;
|
||||
Notifications = notifications;
|
||||
Music = music;
|
||||
TileSet = tileSet;
|
||||
Sequences = sequences;
|
||||
Actors = new ReadOnlyDictionary<string, ActorInfo>(actors);
|
||||
Weapons = new ReadOnlyDictionary<string, WeaponInfo>(weapons);
|
||||
Voices = new ReadOnlyDictionary<string, SoundInfo>(voices);
|
||||
Notifications = new ReadOnlyDictionary<string, SoundInfo>(notifications);
|
||||
Music = new ReadOnlyDictionary<string, MusicInfo>(music);
|
||||
TileSets = new ReadOnlyDictionary<string, TileSet>(tileSets);
|
||||
Sequences = new ReadOnlyDictionary<string, SequenceProvider>(sequences);
|
||||
|
||||
foreach (var a in Actors.Values)
|
||||
{
|
||||
@@ -83,172 +79,5 @@ namespace OpenRA
|
||||
}
|
||||
|
||||
public IEnumerable<KeyValuePair<string, MusicInfo>> InstalledMusic { get { return Music.Where(m => m.Value.Exists); } }
|
||||
|
||||
static IReadOnlyDictionary<string, T> MergeOrDefault<T>(string name, IReadOnlyFileSystem fileSystem, IEnumerable<string> files, MiniYaml additional,
|
||||
IReadOnlyDictionary<string, T> defaults, Func<MiniYamlNode, T> makeObject)
|
||||
{
|
||||
if (additional == null && defaults != null)
|
||||
return defaults;
|
||||
|
||||
var result = MiniYaml.Load(fileSystem, files, additional)
|
||||
.ToDictionaryWithConflictLog(k => k.Key.ToLowerInvariant(), makeObject, "LoadFromManifest<" + name + ">");
|
||||
|
||||
return new ReadOnlyDictionary<string, T>(result);
|
||||
}
|
||||
|
||||
public static Ruleset LoadDefaults(ModData modData)
|
||||
{
|
||||
var m = modData.Manifest;
|
||||
var fs = modData.DefaultFileSystem;
|
||||
|
||||
Ruleset ruleset = null;
|
||||
Action f = () =>
|
||||
{
|
||||
var actors = MergeOrDefault("Manifest,Rules", fs, m.Rules, null, null,
|
||||
k => new ActorInfo(modData.ObjectCreator, k.Key.ToLowerInvariant(), k.Value));
|
||||
|
||||
var weapons = MergeOrDefault("Manifest,Weapons", fs, m.Weapons, null, null,
|
||||
k => new WeaponInfo(k.Key.ToLowerInvariant(), k.Value));
|
||||
|
||||
var voices = MergeOrDefault("Manifest,Voices", fs, m.Voices, null, null,
|
||||
k => new SoundInfo(k.Value));
|
||||
|
||||
var notifications = MergeOrDefault("Manifest,Notifications", fs, m.Notifications, null, null,
|
||||
k => new SoundInfo(k.Value));
|
||||
|
||||
var music = MergeOrDefault("Manifest,Music", fs, m.Music, null, null,
|
||||
k => new MusicInfo(k.Key, k.Value));
|
||||
|
||||
// The default ruleset does not include a preferred tileset or sequence set
|
||||
ruleset = new Ruleset(actors, weapons, voices, notifications, music, null, null);
|
||||
};
|
||||
|
||||
if (modData.IsOnMainThread)
|
||||
{
|
||||
modData.HandleLoadingProgress();
|
||||
|
||||
var loader = new Task(f);
|
||||
loader.Start();
|
||||
|
||||
// Animate the loadscreen while we wait
|
||||
while (!loader.Wait(40))
|
||||
modData.HandleLoadingProgress();
|
||||
}
|
||||
else
|
||||
f();
|
||||
|
||||
return ruleset;
|
||||
}
|
||||
|
||||
public static Ruleset LoadDefaultsForTileSet(ModData modData, string tileSet)
|
||||
{
|
||||
var dr = modData.DefaultRules;
|
||||
var ts = modData.DefaultTileSets[tileSet];
|
||||
var sequences = modData.DefaultSequences[tileSet];
|
||||
return new Ruleset(dr.Actors, dr.Weapons, dr.Voices, dr.Notifications, dr.Music, ts, sequences);
|
||||
}
|
||||
|
||||
public static Ruleset Load(ModData modData, IReadOnlyFileSystem fileSystem, string tileSet,
|
||||
MiniYaml mapRules, MiniYaml mapWeapons, MiniYaml mapVoices, MiniYaml mapNotifications,
|
||||
MiniYaml mapMusic, MiniYaml mapSequences)
|
||||
{
|
||||
var m = modData.Manifest;
|
||||
var dr = modData.DefaultRules;
|
||||
|
||||
Ruleset ruleset = null;
|
||||
Action f = () =>
|
||||
{
|
||||
var actors = MergeOrDefault("Rules", fileSystem, m.Rules, mapRules, dr.Actors,
|
||||
k => new ActorInfo(modData.ObjectCreator, k.Key.ToLowerInvariant(), k.Value));
|
||||
|
||||
var weapons = MergeOrDefault("Weapons", fileSystem, m.Weapons, mapWeapons, dr.Weapons,
|
||||
k => new WeaponInfo(k.Key.ToLowerInvariant(), k.Value));
|
||||
|
||||
var voices = MergeOrDefault("Voices", fileSystem, m.Voices, mapVoices, dr.Voices,
|
||||
k => new SoundInfo(k.Value));
|
||||
|
||||
var notifications = MergeOrDefault("Notifications", fileSystem, m.Notifications, mapNotifications, dr.Notifications,
|
||||
k => new SoundInfo(k.Value));
|
||||
|
||||
var music = MergeOrDefault("Music", fileSystem, m.Music, mapMusic, dr.Music,
|
||||
k => new MusicInfo(k.Key, k.Value));
|
||||
|
||||
// TODO: Add support for merging custom tileset modifications
|
||||
var ts = modData.DefaultTileSets[tileSet];
|
||||
|
||||
// TODO: Top-level dictionary should be moved into the Ruleset instead of in its own object
|
||||
var sequences = mapSequences == null ? modData.DefaultSequences[tileSet] :
|
||||
new SequenceProvider(fileSystem, modData, ts, mapSequences);
|
||||
|
||||
// TODO: Add support for custom voxel sequences
|
||||
ruleset = new Ruleset(actors, weapons, voices, notifications, music, ts, sequences);
|
||||
};
|
||||
|
||||
if (modData.IsOnMainThread)
|
||||
{
|
||||
modData.HandleLoadingProgress();
|
||||
|
||||
var loader = new Task(f);
|
||||
loader.Start();
|
||||
|
||||
// Animate the loadscreen while we wait
|
||||
while (!loader.Wait(40))
|
||||
modData.HandleLoadingProgress();
|
||||
}
|
||||
else
|
||||
f();
|
||||
|
||||
return ruleset;
|
||||
}
|
||||
|
||||
static bool AnyCustomYaml(MiniYaml yaml)
|
||||
{
|
||||
return yaml != null && (yaml.Value != null || yaml.Nodes.Any());
|
||||
}
|
||||
|
||||
static bool AnyFlaggedTraits(ModData modData, List<MiniYamlNode> actors)
|
||||
{
|
||||
foreach (var actorNode in actors)
|
||||
{
|
||||
foreach (var traitNode in actorNode.Value.Nodes)
|
||||
{
|
||||
try
|
||||
{
|
||||
var traitName = traitNode.Key.Split('@')[0];
|
||||
var traitType = modData.ObjectCreator.FindType(traitName + "Info");
|
||||
if (traitType.GetInterface("ILobbyCustomRulesIgnore") == null)
|
||||
return true;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool DefinesUnsafeCustomRules(ModData modData, IReadOnlyFileSystem fileSystem,
|
||||
MiniYaml mapRules, MiniYaml mapWeapons, MiniYaml mapVoices, MiniYaml mapNotifications, MiniYaml mapSequences)
|
||||
{
|
||||
// Maps that define any weapon, voice, notification, or sequence overrides are always flagged
|
||||
if (AnyCustomYaml(mapWeapons) || AnyCustomYaml(mapVoices) || AnyCustomYaml(mapNotifications) || AnyCustomYaml(mapSequences))
|
||||
return true;
|
||||
|
||||
// Any trait overrides that aren't explicitly whitelisted are flagged
|
||||
if (mapRules != null)
|
||||
{
|
||||
if (AnyFlaggedTraits(modData, mapRules.Nodes))
|
||||
return true;
|
||||
|
||||
if (mapRules.Value != null)
|
||||
{
|
||||
var mapFiles = FieldLoader.GetValue<string[]>("value", mapRules.Value);
|
||||
foreach (var f in mapFiles)
|
||||
if (AnyFlaggedTraits(modData, MiniYaml.FromStream(fileSystem.Open(f))))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
159
OpenRA.Game/GameRules/RulesetCache.cs
Normal file
159
OpenRA.Game/GameRules/RulesetCache.cs
Normal file
@@ -0,0 +1,159 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2015 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 COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.GameRules;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Support;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
public sealed class RulesetCache : IDisposable
|
||||
{
|
||||
static readonly List<MiniYamlNode> NoMapRules = new List<MiniYamlNode>();
|
||||
|
||||
readonly ModData modData;
|
||||
|
||||
readonly Dictionary<string, ActorInfo> actorCache = new Dictionary<string, ActorInfo>();
|
||||
readonly Dictionary<string, WeaponInfo> weaponCache = new Dictionary<string, WeaponInfo>();
|
||||
readonly Dictionary<string, SoundInfo> voiceCache = new Dictionary<string, SoundInfo>();
|
||||
readonly Dictionary<string, SoundInfo> notificationCache = new Dictionary<string, SoundInfo>();
|
||||
readonly Dictionary<string, MusicInfo> musicCache = new Dictionary<string, MusicInfo>();
|
||||
readonly Dictionary<string, TileSet> tileSetCache = new Dictionary<string, TileSet>();
|
||||
readonly Dictionary<string, SequenceCache> sequenceCaches = new Dictionary<string, SequenceCache>();
|
||||
|
||||
public event EventHandler LoadingProgress;
|
||||
void RaiseProgress()
|
||||
{
|
||||
if (LoadingProgress != null)
|
||||
LoadingProgress(this, new EventArgs());
|
||||
}
|
||||
|
||||
public RulesetCache(ModData modData)
|
||||
{
|
||||
this.modData = modData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cache and return the Ruleset for a given map.
|
||||
/// If a map isn't specified then return the default mod Ruleset.
|
||||
/// </summary>
|
||||
public Ruleset Load(Map map = null)
|
||||
{
|
||||
var m = modData.Manifest;
|
||||
|
||||
Dictionary<string, ActorInfo> actors;
|
||||
Dictionary<string, WeaponInfo> weapons;
|
||||
Dictionary<string, SoundInfo> voices;
|
||||
Dictionary<string, SoundInfo> notifications;
|
||||
Dictionary<string, MusicInfo> music;
|
||||
Dictionary<string, TileSet> tileSets;
|
||||
|
||||
using (new PerfTimer("Actors"))
|
||||
actors = LoadYamlRules(actorCache, m.Rules,
|
||||
map != null ? map.RuleDefinitions : NoMapRules,
|
||||
(k, y) => new ActorInfo(k.Key.ToLowerInvariant(), k.Value, y));
|
||||
|
||||
using (new PerfTimer("Weapons"))
|
||||
weapons = LoadYamlRules(weaponCache, m.Weapons,
|
||||
map != null ? map.WeaponDefinitions : NoMapRules,
|
||||
(k, _) => new WeaponInfo(k.Key.ToLowerInvariant(), k.Value));
|
||||
|
||||
using (new PerfTimer("Voices"))
|
||||
voices = LoadYamlRules(voiceCache, m.Voices,
|
||||
map != null ? map.VoiceDefinitions : NoMapRules,
|
||||
(k, _) => new SoundInfo(k.Value));
|
||||
|
||||
using (new PerfTimer("Notifications"))
|
||||
notifications = LoadYamlRules(notificationCache, m.Notifications,
|
||||
map != null ? map.NotificationDefinitions : NoMapRules,
|
||||
(k, _) => new SoundInfo(k.Value));
|
||||
|
||||
using (new PerfTimer("Music"))
|
||||
music = LoadYamlRules(musicCache, m.Music,
|
||||
map != null ? map.MusicDefinitions : NoMapRules,
|
||||
(k, _) => new MusicInfo(k.Key, k.Value));
|
||||
|
||||
using (new PerfTimer("TileSets"))
|
||||
tileSets = LoadTileSets(tileSetCache, sequenceCaches, m.TileSets);
|
||||
|
||||
var sequences = sequenceCaches.ToDictionary(kvp => kvp.Key, kvp => new SequenceProvider(kvp.Value, map));
|
||||
return new Ruleset(actors, weapons, voices, notifications, music, tileSets, sequences);
|
||||
}
|
||||
|
||||
Dictionary<string, T> LoadYamlRules<T>(
|
||||
Dictionary<string, T> itemCache,
|
||||
string[] files, List<MiniYamlNode> nodes,
|
||||
Func<MiniYamlNode, Dictionary<string, MiniYaml>, T> f)
|
||||
{
|
||||
RaiseProgress();
|
||||
|
||||
var inputKey = string.Concat(string.Join("|", files), "|", nodes.WriteToString());
|
||||
|
||||
var mergedNodes = files
|
||||
.Select(s => MiniYaml.FromFile(s))
|
||||
.Aggregate(nodes, MiniYaml.MergeLiberal);
|
||||
|
||||
Func<MiniYamlNode, Dictionary<string, MiniYaml>, T> wrap = (wkv, wyy) =>
|
||||
{
|
||||
var key = inputKey + wkv.Value.ToLines(wkv.Key).JoinWith("|");
|
||||
T t;
|
||||
if (itemCache.TryGetValue(key, out t))
|
||||
return t;
|
||||
|
||||
t = f(wkv, wyy);
|
||||
itemCache.Add(key, t);
|
||||
|
||||
RaiseProgress();
|
||||
return t;
|
||||
};
|
||||
|
||||
var yy = mergedNodes.ToDictionary(x => x.Key, x => x.Value);
|
||||
var itemSet = mergedNodes.ToDictionaryWithConflictLog(kv => kv.Key.ToLowerInvariant(), kv => wrap(kv, yy), "LoadYamlRules", null, null);
|
||||
|
||||
RaiseProgress();
|
||||
return itemSet;
|
||||
}
|
||||
|
||||
Dictionary<string, TileSet> LoadTileSets(Dictionary<string, TileSet> itemCache, Dictionary<string, SequenceCache> sequenceCaches, string[] files)
|
||||
{
|
||||
var items = new Dictionary<string, TileSet>();
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
TileSet t;
|
||||
if (itemCache.TryGetValue(file, out t))
|
||||
items.Add(t.Id, t);
|
||||
else
|
||||
{
|
||||
t = new TileSet(modData, file);
|
||||
itemCache.Add(file, t);
|
||||
|
||||
// every time we load a tile set, we create a sequence cache for it
|
||||
var sc = new SequenceCache(modData, t);
|
||||
sequenceCaches.Add(t.Id, sc);
|
||||
|
||||
items.Add(t.Id, t);
|
||||
}
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var cache in sequenceCaches.Values)
|
||||
cache.Dispose();
|
||||
sequenceCaches.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
@@ -25,7 +24,6 @@ namespace OpenRA.GameRules
|
||||
public int[] RangeModifiers;
|
||||
public int Facing;
|
||||
public WPos Source;
|
||||
public Func<WPos> CurrentSource;
|
||||
public Actor SourceActor;
|
||||
public WPos PassiveTarget;
|
||||
public Target GuidedTarget;
|
||||
@@ -47,6 +45,8 @@ namespace OpenRA.GameRules
|
||||
[Desc("Number of shots in a single ammo magazine.")]
|
||||
public readonly int Burst = 1;
|
||||
|
||||
public readonly bool Charges = false;
|
||||
|
||||
[Desc("What types of targets are affected.")]
|
||||
public readonly HashSet<string> ValidTargets = new HashSet<string> { "Ground", "Water" };
|
||||
|
||||
@@ -126,17 +126,14 @@ namespace OpenRA.GameRules
|
||||
/// <summary>Checks if the weapon is valid against (can target) the actor.</summary>
|
||||
public bool IsValidAgainst(Actor victim, Actor firedBy)
|
||||
{
|
||||
var targetTypes = victim.GetEnabledTargetTypes();
|
||||
|
||||
if (!IsValidTarget(targetTypes))
|
||||
var targetable = victim.TraitsImplementing<ITargetable>().Where(Exts.IsTraitEnabled);
|
||||
if (!IsValidTarget(targetable.SelectMany(t => t.TargetTypes)))
|
||||
return false;
|
||||
|
||||
// PERF: Avoid LINQ.
|
||||
foreach (var warhead in Warheads)
|
||||
if (warhead.IsValidAgainst(victim, firedBy))
|
||||
return true;
|
||||
if (!Warheads.Any(w => w.IsValidAgainst(victim, firedBy)))
|
||||
return false;
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>Checks if the weapon is valid against (can target) the frozen actor.</summary>
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Graphics;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Meebey.SmartIrc4net;
|
||||
using OpenRA;
|
||||
using OpenRA.Primitives;
|
||||
|
||||
namespace OpenRA.Chat
|
||||
@@ -65,7 +66,7 @@ namespace OpenRA.Chat
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class GlobalChat : IDisposable
|
||||
public class GlobalChat : IDisposable
|
||||
{
|
||||
readonly IrcClient client = new IrcClient();
|
||||
volatile Channel channel;
|
||||
@@ -106,8 +107,6 @@ namespace OpenRA.Chat
|
||||
client.OnDevoice += (_, e) => SetUserVoiced(e.Whom, false);
|
||||
client.OnPart += OnPart;
|
||||
client.OnQuit += OnQuit;
|
||||
|
||||
TrySetNickname(Game.Settings.Player.Name);
|
||||
}
|
||||
|
||||
void SetUserOp(string whom, bool isOp)
|
||||
@@ -226,22 +225,14 @@ namespace OpenRA.Chat
|
||||
|
||||
void OnKick(object sender, KickEventArgs e)
|
||||
{
|
||||
if (e.Whom == client.Nickname)
|
||||
{
|
||||
Disconnect();
|
||||
connectionStatus = ChatConnectionStatus.Error;
|
||||
AddNotification("You were kicked from the chat by {0}. ({1})".F(e.Who, e.KickReason));
|
||||
}
|
||||
else
|
||||
{
|
||||
Users.Remove(e.Whom);
|
||||
AddNotification("{0} was kicked from the chat by {1}. ({2})".F(e.Whom, e.Who, e.KickReason));
|
||||
}
|
||||
Disconnect();
|
||||
connectionStatus = ChatConnectionStatus.Error;
|
||||
AddNotification("Error: You were kicked from the chat by {0}".F(e.Who));
|
||||
}
|
||||
|
||||
void OnJoin(object sender, JoinEventArgs e)
|
||||
{
|
||||
if (e.Who == client.Nickname || channel == null || e.Channel != channel.Name)
|
||||
if (e.Who == client.Nickname || e.Channel != channel.Name)
|
||||
return;
|
||||
|
||||
AddNotification("{0} joined the chat.".F(e.Who));
|
||||
@@ -284,7 +275,7 @@ namespace OpenRA.Chat
|
||||
|
||||
void OnPart(object sender, PartEventArgs e)
|
||||
{
|
||||
if (channel == null || e.Data.Channel != channel.Name)
|
||||
if (e.Data.Channel != channel.Name)
|
||||
return;
|
||||
|
||||
AddNotification("{0} left the chat.".F(e.Who));
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
@@ -18,35 +17,36 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
public class Animation
|
||||
{
|
||||
readonly int defaultTick = 40; // 25 fps == 40 ms
|
||||
public ISpriteSequence CurrentSequence { get; private set; }
|
||||
public string Name { get; private set; }
|
||||
public bool IsDecoration { get; set; }
|
||||
public bool IsDecoration = false;
|
||||
public Func<bool> Paused;
|
||||
|
||||
readonly Func<int> facingFunc;
|
||||
|
||||
int frame = 0;
|
||||
bool backwards = false;
|
||||
|
||||
string name;
|
||||
|
||||
bool tickAlways;
|
||||
|
||||
public string Name { get { return name; } }
|
||||
|
||||
readonly SequenceProvider sequenceProvider;
|
||||
readonly Func<int> facingFunc;
|
||||
readonly Func<bool> paused;
|
||||
|
||||
int frame;
|
||||
bool backwards;
|
||||
bool tickAlways;
|
||||
int timeUntilNextFrame;
|
||||
Action tickFunc = () => { };
|
||||
|
||||
public Animation(World world, string name)
|
||||
: this(world, name, () => 0) { }
|
||||
|
||||
public Animation(World world, string name, Func<int> facingFunc)
|
||||
: this(world, name, facingFunc, null) { }
|
||||
: this(world.Map.SequenceProvider, name, facingFunc) { }
|
||||
|
||||
public Animation(World world, string name, Func<bool> paused)
|
||||
: this(world, name, () => 0, paused) { }
|
||||
|
||||
public Animation(World world, string name, Func<int> facingFunc, Func<bool> paused)
|
||||
public Animation(SequenceProvider sequenceProvider, string name, Func<int> facingFunc)
|
||||
{
|
||||
sequenceProvider = world.Map.Rules.Sequences;
|
||||
Name = name.ToLowerInvariant();
|
||||
this.sequenceProvider = sequenceProvider;
|
||||
this.name = name.ToLowerInvariant();
|
||||
this.tickFunc = () => { };
|
||||
this.facingFunc = facingFunc;
|
||||
this.paused = paused;
|
||||
}
|
||||
|
||||
public int CurrentFrame { get { return backwards ? CurrentSequence.Start + CurrentSequence.Length - frame - 1 : frame; } }
|
||||
@@ -76,23 +76,12 @@ namespace OpenRA.Graphics
|
||||
PlayThen(sequenceName, null);
|
||||
}
|
||||
|
||||
int CurrentSequenceTickOrDefault()
|
||||
{
|
||||
const int DefaultTick = 40; // 25 fps == 40 ms
|
||||
return CurrentSequence != null ? CurrentSequence.Tick : DefaultTick;
|
||||
}
|
||||
|
||||
void PlaySequence(string sequenceName)
|
||||
{
|
||||
CurrentSequence = GetSequence(sequenceName);
|
||||
timeUntilNextFrame = CurrentSequenceTickOrDefault();
|
||||
}
|
||||
|
||||
public void PlayRepeating(string sequenceName)
|
||||
{
|
||||
backwards = false;
|
||||
tickAlways = false;
|
||||
PlaySequence(sequenceName);
|
||||
CurrentSequence = sequenceProvider.GetSequence(name, sequenceName);
|
||||
timeUntilNextFrame = CurrentSequence != null ? CurrentSequence.Tick : defaultTick;
|
||||
|
||||
frame = 0;
|
||||
tickFunc = () =>
|
||||
@@ -108,8 +97,9 @@ namespace OpenRA.Graphics
|
||||
if (!HasSequence(sequenceName))
|
||||
return false;
|
||||
|
||||
CurrentSequence = GetSequence(sequenceName);
|
||||
timeUntilNextFrame = Math.Min(CurrentSequenceTickOrDefault(), timeUntilNextFrame);
|
||||
CurrentSequence = sequenceProvider.GetSequence(name, sequenceName);
|
||||
var tick = CurrentSequence != null ? CurrentSequence.Tick : defaultTick;
|
||||
timeUntilNextFrame = Math.Min(tick, timeUntilNextFrame);
|
||||
frame %= CurrentSequence.Length;
|
||||
return true;
|
||||
}
|
||||
@@ -118,7 +108,8 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
backwards = false;
|
||||
tickAlways = false;
|
||||
PlaySequence(sequenceName);
|
||||
CurrentSequence = sequenceProvider.GetSequence(name, sequenceName);
|
||||
timeUntilNextFrame = CurrentSequence != null ? CurrentSequence.Tick : defaultTick;
|
||||
|
||||
frame = 0;
|
||||
tickFunc = () =>
|
||||
@@ -143,7 +134,8 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
backwards = false;
|
||||
tickAlways = true;
|
||||
PlaySequence(sequenceName);
|
||||
CurrentSequence = sequenceProvider.GetSequence(name, sequenceName);
|
||||
timeUntilNextFrame = CurrentSequence != null ? CurrentSequence.Tick : defaultTick;
|
||||
|
||||
frame = func();
|
||||
tickFunc = () => frame = func();
|
||||
@@ -152,7 +144,8 @@ namespace OpenRA.Graphics
|
||||
public void PlayFetchDirection(string sequenceName, Func<int> direction)
|
||||
{
|
||||
tickAlways = false;
|
||||
PlaySequence(sequenceName);
|
||||
CurrentSequence = sequenceProvider.GetSequence(name, sequenceName);
|
||||
timeUntilNextFrame = CurrentSequence != null ? CurrentSequence.Tick : defaultTick;
|
||||
|
||||
frame = 0;
|
||||
tickFunc = () =>
|
||||
@@ -166,12 +159,17 @@ namespace OpenRA.Graphics
|
||||
};
|
||||
}
|
||||
|
||||
int timeUntilNextFrame;
|
||||
Action tickFunc;
|
||||
|
||||
public void Tick()
|
||||
{
|
||||
if (paused == null || !paused())
|
||||
if (Paused == null || !Paused())
|
||||
Tick(40); // tick one frame
|
||||
}
|
||||
|
||||
public bool HasSequence(string seq) { return sequenceProvider.HasSequence(name, seq); }
|
||||
|
||||
public void Tick(int t)
|
||||
{
|
||||
if (tickAlways)
|
||||
@@ -182,7 +180,7 @@ namespace OpenRA.Graphics
|
||||
while (timeUntilNextFrame <= 0)
|
||||
{
|
||||
tickFunc();
|
||||
timeUntilNextFrame += CurrentSequenceTickOrDefault();
|
||||
timeUntilNextFrame += CurrentSequence != null ? CurrentSequence.Tick : defaultTick;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -191,19 +189,17 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
newImage = newImage.ToLowerInvariant();
|
||||
|
||||
if (Name != newImage)
|
||||
if (name != newImage)
|
||||
{
|
||||
Name = newImage;
|
||||
name = newImage.ToLowerInvariant();
|
||||
if (!ReplaceAnim(CurrentSequence.Name))
|
||||
ReplaceAnim(newAnimIfMissing);
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasSequence(string seq) { return sequenceProvider.HasSequence(Name, seq); }
|
||||
|
||||
public ISpriteSequence GetSequence(string sequenceName)
|
||||
{
|
||||
return sequenceProvider.GetSequence(Name, sequenceName);
|
||||
return sequenceProvider.GetSequence(name, sequenceName);
|
||||
}
|
||||
|
||||
public string GetRandomExistingSequence(string[] sequences, MersenneTwister random)
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
@@ -19,20 +18,22 @@ namespace OpenRA.Graphics
|
||||
public readonly Animation Animation;
|
||||
public readonly Func<WVec> OffsetFunc;
|
||||
public readonly Func<bool> DisableFunc;
|
||||
public readonly Func<bool> Paused;
|
||||
public readonly Func<WPos, int> ZOffset;
|
||||
|
||||
public AnimationWithOffset(Animation a, Func<WVec> offset, Func<bool> disable)
|
||||
: this(a, offset, disable, null) { }
|
||||
: this(a, offset, disable, () => false, null) { }
|
||||
|
||||
public AnimationWithOffset(Animation a, Func<WVec> offset, Func<bool> disable, int zOffset)
|
||||
: this(a, offset, disable, _ => zOffset) { }
|
||||
: this(a, offset, disable, () => false, _ => zOffset) { }
|
||||
|
||||
public AnimationWithOffset(Animation a, Func<WVec> offset, Func<bool> disable, Func<WPos, int> zOffset)
|
||||
public AnimationWithOffset(Animation a, Func<WVec> offset, Func<bool> disable, Func<bool> pause, Func<WPos, int> zOffset)
|
||||
{
|
||||
Animation = a;
|
||||
OffsetFunc = offset;
|
||||
DisableFunc = disable;
|
||||
ZOffset = zOffset;
|
||||
this.Animation = a;
|
||||
this.Animation.Paused = pause;
|
||||
this.OffsetFunc = offset;
|
||||
this.DisableFunc = disable;
|
||||
this.ZOffset = zOffset;
|
||||
}
|
||||
|
||||
public IEnumerable<IRenderable> Render(Actor self, WorldRenderer wr, PaletteReference pal, float scale)
|
||||
@@ -46,7 +47,7 @@ namespace OpenRA.Graphics
|
||||
|
||||
public static implicit operator AnimationWithOffset(Animation a)
|
||||
{
|
||||
return new AnimationWithOffset(a, null, null, null);
|
||||
return new AnimationWithOffset(a, null, null, null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,15 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.FileSystem;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
@@ -26,19 +24,16 @@ namespace OpenRA.Graphics
|
||||
static Dictionary<string, Collection> collections;
|
||||
static Dictionary<string, Sheet> cachedSheets;
|
||||
static Dictionary<string, Dictionary<string, Sprite>> cachedSprites;
|
||||
static IReadOnlyFileSystem fileSystem;
|
||||
|
||||
public static void Initialize(ModData modData)
|
||||
public static void Initialize(IEnumerable<string> chromeFiles)
|
||||
{
|
||||
Deinitialize();
|
||||
|
||||
fileSystem = modData.DefaultFileSystem;
|
||||
collections = new Dictionary<string, Collection>();
|
||||
cachedSheets = new Dictionary<string, Sheet>();
|
||||
cachedSprites = new Dictionary<string, Dictionary<string, Sprite>>();
|
||||
|
||||
var chrome = MiniYaml.Merge(modData.Manifest.Chrome
|
||||
.Select(s => MiniYaml.FromStream(fileSystem.Open(s))));
|
||||
var chrome = chromeFiles.Select(s => MiniYaml.FromFile(s)).Aggregate(MiniYaml.MergeLiberal);
|
||||
|
||||
foreach (var c in chrome)
|
||||
LoadCollection(c.Key, c.Value);
|
||||
@@ -88,9 +83,6 @@ namespace OpenRA.Graphics
|
||||
|
||||
public static Sprite GetImage(string collectionName, string imageName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(collectionName))
|
||||
return null;
|
||||
|
||||
// Cached sprite
|
||||
Dictionary<string, Sprite> cachedCollection;
|
||||
Sprite sprite;
|
||||
@@ -114,9 +106,7 @@ namespace OpenRA.Graphics
|
||||
sheet = cachedSheets[mi.Src];
|
||||
else
|
||||
{
|
||||
using (var stream = fileSystem.Open(mi.Src))
|
||||
sheet = new Sheet(SheetType.BGRA, stream);
|
||||
|
||||
sheet = new Sheet(SheetType.BGRA, mi.Src);
|
||||
cachedSheets.Add(mi.Src, sheet);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.FileSystem;
|
||||
using OpenRA.Primitives;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
@@ -22,13 +24,11 @@ namespace OpenRA.Graphics
|
||||
|
||||
public CursorProvider(ModData modData)
|
||||
{
|
||||
var fileSystem = modData.DefaultFileSystem;
|
||||
var sequenceYaml = MiniYaml.Merge(modData.Manifest.Cursors.Select(
|
||||
s => MiniYaml.FromStream(fileSystem.Open(s))));
|
||||
|
||||
var sequenceFiles = modData.Manifest.Cursors;
|
||||
var sequences = new MiniYaml(null, sequenceFiles.Select(s => MiniYaml.FromFile(s)).Aggregate(MiniYaml.MergeLiberal));
|
||||
var shadowIndex = new int[] { };
|
||||
|
||||
var nodesDict = new MiniYaml(null, sequenceYaml).ToDictionary();
|
||||
var nodesDict = sequences.ToDictionary();
|
||||
if (nodesDict.ContainsKey("ShadowIndex"))
|
||||
{
|
||||
Array.Resize(ref shadowIndex, shadowIndex.Length + 1);
|
||||
@@ -38,11 +38,11 @@ namespace OpenRA.Graphics
|
||||
|
||||
var palettes = new Dictionary<string, ImmutablePalette>();
|
||||
foreach (var p in nodesDict["Palettes"].Nodes)
|
||||
palettes.Add(p.Key, new ImmutablePalette(fileSystem.Open(p.Value.Value), shadowIndex));
|
||||
palettes.Add(p.Key, new ImmutablePalette(GlobalFileSystem.Open(p.Value.Value), shadowIndex));
|
||||
|
||||
Palettes = palettes.AsReadOnly();
|
||||
|
||||
var frameCache = new FrameCache(fileSystem, modData.SpriteLoaders);
|
||||
var frameCache = new FrameCache(modData.SpriteLoaders);
|
||||
var cursors = new Dictionary<string, CursorSequence>();
|
||||
foreach (var s in nodesDict["Cursors"].Nodes)
|
||||
foreach (var sequence in s.Value.Nodes)
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using OpenRA.Scripting;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
@@ -29,17 +27,13 @@ namespace OpenRA.Graphics
|
||||
return new HSLColor((byte)(255 * h), (byte)(255 * ss), (byte)(255 * ll));
|
||||
}
|
||||
|
||||
public HSLColor(Color color)
|
||||
{
|
||||
RGB = color;
|
||||
H = (byte)((color.GetHue() / 360.0f) * 255);
|
||||
S = (byte)(color.GetSaturation() * 255);
|
||||
L = (byte)(color.GetBrightness() * 255);
|
||||
}
|
||||
|
||||
public static HSLColor FromRGB(int r, int g, int b)
|
||||
{
|
||||
return new HSLColor(Color.FromArgb(r, g, b));
|
||||
var c = Color.FromArgb(r, g, b);
|
||||
var h = (byte)((c.GetHue() / 360.0f) * 255);
|
||||
var s = (byte)(c.GetSaturation() * 255);
|
||||
var l = (byte)(c.GetBrightness() * 255);
|
||||
return new HSLColor(h, s, l);
|
||||
}
|
||||
|
||||
public static Color RGBFromHSL(float h, float s, float l)
|
||||
@@ -72,27 +66,6 @@ namespace OpenRA.Graphics
|
||||
return Color.FromArgb((int)(rgb[0] * 255), (int)(rgb[1] * 255), (int)(rgb[2] * 255));
|
||||
}
|
||||
|
||||
public static bool TryParseRGB(string value, out Color color)
|
||||
{
|
||||
color = new Color();
|
||||
value = value.Trim();
|
||||
if (value.Length != 6 && value.Length != 8)
|
||||
return false;
|
||||
|
||||
byte red, green, blue, alpha = 255;
|
||||
if (!byte.TryParse(value.Substring(0, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out red)
|
||||
|| !byte.TryParse(value.Substring(2, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out green)
|
||||
|| !byte.TryParse(value.Substring(4, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out blue))
|
||||
return false;
|
||||
|
||||
if (value.Length == 8
|
||||
&& !byte.TryParse(value.Substring(6, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out alpha))
|
||||
return false;
|
||||
|
||||
color = Color.FromArgb(alpha, red, green, blue);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool operator ==(HSLColor me, HSLColor other)
|
||||
{
|
||||
return me.H == other.H && me.S == other.S && me.L == other.L;
|
||||
@@ -123,18 +96,6 @@ namespace OpenRA.Graphics
|
||||
return "{0},{1},{2}".F(H, S, L);
|
||||
}
|
||||
|
||||
public static string ToHexString(Color color)
|
||||
{
|
||||
if (color.A == 255)
|
||||
return color.R.ToString("X2") + color.G.ToString("X2") + color.B.ToString("X2");
|
||||
return color.R.ToString("X2") + color.G.ToString("X2") + color.B.ToString("X2") + color.A.ToString("X2");
|
||||
}
|
||||
|
||||
public string ToHexString()
|
||||
{
|
||||
return ToHexString(RGB);
|
||||
}
|
||||
|
||||
public override int GetHashCode() { return H.GetHashCode() ^ S.GetHashCode() ^ L.GetHashCode(); }
|
||||
|
||||
public override bool Equals(object obj)
|
||||
|
||||
@@ -12,10 +12,12 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Primitives;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
public sealed class HardwareCursor : ICursor
|
||||
public class HardwareCursor : ICursor
|
||||
{
|
||||
readonly Dictionary<string, IHardwareCursor[]> hardwareCursors = new Dictionary<string, IHardwareCursor[]>();
|
||||
readonly CursorProvider cursorProvider;
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
@@ -62,9 +61,9 @@ namespace OpenRA
|
||||
Bitmap TakeScreenshot();
|
||||
void PumpInput(IInputHandler inputHandler);
|
||||
string GetClipboardText();
|
||||
bool SetClipboardText(string text);
|
||||
void DrawPrimitives(PrimitiveType type, int firstVertex, int numVertices);
|
||||
|
||||
void SetLineWidth(float width);
|
||||
void EnableScissor(int left, int top, int width, int height);
|
||||
void DisableScissor();
|
||||
|
||||
@@ -78,8 +77,6 @@ namespace OpenRA
|
||||
|
||||
IHardwareCursor CreateHardwareCursor(string name, Size size, byte[] data, int2 hotspot);
|
||||
void SetHardwareCursor(IHardwareCursor cursor);
|
||||
|
||||
string GLVersion { get; }
|
||||
}
|
||||
|
||||
public interface IVertexBuffer<T> : IDisposable
|
||||
@@ -125,6 +122,7 @@ namespace OpenRA
|
||||
PointList,
|
||||
LineList,
|
||||
TriangleList,
|
||||
QuadList,
|
||||
}
|
||||
|
||||
public struct Range<T>
|
||||
|
||||
174
OpenRA.Game/Graphics/LineRenderer.cs
Normal file
174
OpenRA.Game/Graphics/LineRenderer.cs
Normal file
@@ -0,0 +1,174 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2015 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 COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
public class LineRenderer : Renderer.IBatchRenderer
|
||||
{
|
||||
static readonly float2 Offset = new float2(0.5f, 0.5f);
|
||||
|
||||
readonly Renderer renderer;
|
||||
readonly IShader shader;
|
||||
readonly Action renderAction;
|
||||
|
||||
readonly Vertex[] vertices;
|
||||
int nv = 0;
|
||||
|
||||
float lineWidth = 1f;
|
||||
|
||||
public LineRenderer(Renderer renderer, IShader shader)
|
||||
{
|
||||
this.renderer = renderer;
|
||||
this.shader = shader;
|
||||
vertices = new Vertex[renderer.TempBufferSize];
|
||||
renderAction = () =>
|
||||
{
|
||||
renderer.SetLineWidth(LineWidth);
|
||||
renderer.DrawBatch(vertices, nv, PrimitiveType.LineList);
|
||||
};
|
||||
}
|
||||
|
||||
public float LineWidth
|
||||
{
|
||||
get
|
||||
{
|
||||
return lineWidth;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (LineWidth != value)
|
||||
Flush();
|
||||
|
||||
lineWidth = value;
|
||||
}
|
||||
}
|
||||
|
||||
public void Flush()
|
||||
{
|
||||
if (nv > 0)
|
||||
{
|
||||
renderer.Device.SetBlendMode(BlendMode.Alpha);
|
||||
shader.Render(renderAction);
|
||||
renderer.Device.SetBlendMode(BlendMode.None);
|
||||
|
||||
nv = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawRect(float2 tl, float2 br, Color c)
|
||||
{
|
||||
var tr = new float2(br.X, tl.Y);
|
||||
var bl = new float2(tl.X, br.Y);
|
||||
DrawLine(tl, tr, c);
|
||||
DrawLine(tl, bl, c);
|
||||
DrawLine(tr, br, c);
|
||||
DrawLine(bl, br, c);
|
||||
}
|
||||
|
||||
public void DrawLine(float2 start, float2 end, Color color)
|
||||
{
|
||||
renderer.CurrentBatchRenderer = this;
|
||||
|
||||
if (nv + 2 > renderer.TempBufferSize)
|
||||
Flush();
|
||||
|
||||
color = Util.PremultiplyAlpha(color);
|
||||
var r = color.R / 255.0f;
|
||||
var g = color.G / 255.0f;
|
||||
var b = color.B / 255.0f;
|
||||
var a = color.A / 255.0f;
|
||||
vertices[nv++] = new Vertex(start + Offset, r, g, b, a);
|
||||
vertices[nv++] = new Vertex(end + Offset, r, g, b, a);
|
||||
}
|
||||
|
||||
public void DrawLine(float2 start, float2 end, Color startColor, Color endColor)
|
||||
{
|
||||
renderer.CurrentBatchRenderer = this;
|
||||
|
||||
if (nv + 2 > renderer.TempBufferSize)
|
||||
Flush();
|
||||
|
||||
startColor = Util.PremultiplyAlpha(startColor);
|
||||
var r = startColor.R / 255.0f;
|
||||
var g = startColor.G / 255.0f;
|
||||
var b = startColor.B / 255.0f;
|
||||
var a = startColor.A / 255.0f;
|
||||
vertices[nv++] = new Vertex(start + Offset, r, g, b, a);
|
||||
|
||||
endColor = Util.PremultiplyAlpha(endColor);
|
||||
r = endColor.R / 255.0f;
|
||||
g = endColor.G / 255.0f;
|
||||
b = endColor.B / 255.0f;
|
||||
a = endColor.A / 255.0f;
|
||||
vertices[nv++] = new Vertex(end + Offset, r, g, b, a);
|
||||
}
|
||||
|
||||
public void DrawLineStrip(IEnumerable<float2> points, Color color)
|
||||
{
|
||||
renderer.CurrentBatchRenderer = this;
|
||||
|
||||
color = Util.PremultiplyAlpha(color);
|
||||
var r = color.R / 255.0f;
|
||||
var g = color.G / 255.0f;
|
||||
var b = color.B / 255.0f;
|
||||
var a = color.A / 255.0f;
|
||||
|
||||
var first = true;
|
||||
var prev = new Vertex();
|
||||
foreach (var point in points)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
first = false;
|
||||
prev = new Vertex(point + Offset, r, g, b, a);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nv + 2 > renderer.TempBufferSize)
|
||||
Flush();
|
||||
|
||||
vertices[nv++] = prev;
|
||||
prev = new Vertex(point + Offset, r, g, b, a);
|
||||
vertices[nv++] = prev;
|
||||
}
|
||||
}
|
||||
|
||||
public void FillRect(RectangleF r, Color color)
|
||||
{
|
||||
for (var y = r.Top; y < r.Bottom; y++)
|
||||
DrawLine(new float2(r.Left, y), new float2(r.Right, y), color);
|
||||
}
|
||||
|
||||
public void FillEllipse(RectangleF r, Color color)
|
||||
{
|
||||
var a = (r.Right - r.Left) / 2;
|
||||
var b = (r.Bottom - r.Top) / 2;
|
||||
var xc = (r.Right + r.Left) / 2;
|
||||
var yc = (r.Bottom + r.Top) / 2;
|
||||
for (var y = r.Top; y <= r.Bottom; y++)
|
||||
{
|
||||
var dx = a * (float)Math.Sqrt(1 - (y - yc) * (y - yc) / b / b);
|
||||
DrawLine(new float2(xc - dx, y), new float2(xc + dx, y), color);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetViewportParams(Size screen, float zoom, int2 scroll)
|
||||
{
|
||||
shader.SetVec("Scroll", scroll.X, scroll.Y);
|
||||
shader.SetVec("r1", zoom * 2f / screen.Width, -zoom * 2f / screen.Height);
|
||||
shader.SetVec("r2", -1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
@@ -38,7 +37,7 @@ namespace OpenRA.Graphics
|
||||
if (defaultSrc != Src)
|
||||
root.Add(new MiniYamlNode("Src", Src));
|
||||
|
||||
return new MiniYaml(FieldSaver.FormatValue(this, GetType().GetField("rect")), root);
|
||||
return new MiniYaml(FieldSaver.FormatValue(this, this.GetType().GetField("rect")), root);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
148
OpenRA.Game/Graphics/Minimap.cs
Normal file
148
OpenRA.Game/Graphics/Minimap.cs
Normal file
@@ -0,0 +1,148 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2015 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 COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Linq;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
public static class Minimap
|
||||
{
|
||||
public static Bitmap TerrainBitmap(TileSet tileset, Map map, bool actualSize = false)
|
||||
{
|
||||
var isRectangularIsometric = map.Grid.Type == MapGridType.RectangularIsometric;
|
||||
var b = map.Bounds;
|
||||
|
||||
// Fudge the heightmap offset by adding as much extra as we need / can.
|
||||
// This tries to correct for our incorrect assumption that MPos == PPos
|
||||
var heightOffset = Math.Min(map.Grid.MaximumTerrainHeight, map.MapSize.Y - b.Bottom);
|
||||
var width = b.Width;
|
||||
var height = b.Height + heightOffset;
|
||||
|
||||
var bitmapWidth = width;
|
||||
if (isRectangularIsometric)
|
||||
bitmapWidth = 2 * bitmapWidth - 1;
|
||||
|
||||
if (!actualSize)
|
||||
bitmapWidth = height = Exts.NextPowerOf2(Math.Max(bitmapWidth, height));
|
||||
|
||||
var terrain = new Bitmap(bitmapWidth, height);
|
||||
|
||||
var bitmapData = terrain.LockBits(terrain.Bounds(),
|
||||
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
|
||||
|
||||
var mapTiles = map.MapTiles.Value;
|
||||
|
||||
unsafe
|
||||
{
|
||||
var colors = (int*)bitmapData.Scan0;
|
||||
var stride = bitmapData.Stride / 4;
|
||||
for (var y = 0; y < height; y++)
|
||||
{
|
||||
for (var x = 0; x < width; x++)
|
||||
{
|
||||
var uv = new MPos(x + b.Left, y + b.Top);
|
||||
var type = tileset.GetTileInfo(mapTiles[uv]);
|
||||
var leftColor = type != null ? type.LeftColor : Color.Black;
|
||||
|
||||
if (isRectangularIsometric)
|
||||
{
|
||||
// Odd rows are shifted right by 1px
|
||||
var dx = uv.V & 1;
|
||||
var rightColor = type != null ? type.RightColor : Color.Black;
|
||||
if (x + dx > 0)
|
||||
colors[y * stride + 2 * x + dx - 1] = leftColor.ToArgb();
|
||||
|
||||
if (2 * x + dx < stride)
|
||||
colors[y * stride + 2 * x + dx] = rightColor.ToArgb();
|
||||
}
|
||||
else
|
||||
colors[y * stride + x] = leftColor.ToArgb();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
terrain.UnlockBits(bitmapData);
|
||||
return terrain;
|
||||
}
|
||||
|
||||
// Add the static resources defined in the map; if the map lives
|
||||
// in a world use AddCustomTerrain instead
|
||||
static Bitmap AddStaticResources(TileSet tileset, Map map, Ruleset resourceRules, Bitmap terrainBitmap)
|
||||
{
|
||||
var terrain = new Bitmap(terrainBitmap);
|
||||
var isRectangularIsometric = map.Grid.Type == MapGridType.RectangularIsometric;
|
||||
var b = map.Bounds;
|
||||
|
||||
// Fudge the heightmap offset by adding as much extra as we need / can
|
||||
// This tries to correct for our incorrect assumption that MPos == PPos
|
||||
var heightOffset = Math.Min(map.Grid.MaximumTerrainHeight, map.MapSize.Y - b.Bottom);
|
||||
var width = b.Width;
|
||||
var height = b.Height + heightOffset;
|
||||
|
||||
var resources = resourceRules.Actors["world"].TraitInfos<ResourceTypeInfo>()
|
||||
.ToDictionary(r => r.ResourceType, r => r.TerrainType);
|
||||
|
||||
var bitmapData = terrain.LockBits(terrain.Bounds(),
|
||||
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
|
||||
|
||||
unsafe
|
||||
{
|
||||
var colors = (int*)bitmapData.Scan0;
|
||||
var stride = bitmapData.Stride / 4;
|
||||
for (var y = 0; y < height; y++)
|
||||
{
|
||||
for (var x = 0; x < width; x++)
|
||||
{
|
||||
var uv = new MPos(x + b.Left, y + b.Top);
|
||||
if (map.MapResources.Value[uv].Type == 0)
|
||||
continue;
|
||||
|
||||
string res;
|
||||
if (!resources.TryGetValue(map.MapResources.Value[uv].Type, out res))
|
||||
continue;
|
||||
|
||||
var color = tileset[tileset.GetTerrainIndex(res)].Color.ToArgb();
|
||||
if (isRectangularIsometric)
|
||||
{
|
||||
// Odd rows are shifted right by 1px
|
||||
var dx = uv.V & 1;
|
||||
if (x + dx > 0)
|
||||
colors[y * stride + 2 * x + dx - 1] = color;
|
||||
|
||||
if (2 * x + dx < stride)
|
||||
colors[y * stride + 2 * x + dx] = color;
|
||||
}
|
||||
else
|
||||
colors[y * stride + x] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
terrain.UnlockBits(bitmapData);
|
||||
|
||||
return terrain;
|
||||
}
|
||||
|
||||
public static Bitmap RenderMapPreview(TileSet tileset, Map map, bool actualSize)
|
||||
{
|
||||
return RenderMapPreview(tileset, map, map.Rules, actualSize);
|
||||
}
|
||||
|
||||
public static Bitmap RenderMapPreview(TileSet tileset, Map map, Ruleset resourceRules, bool actualSize)
|
||||
{
|
||||
using (var terrain = TerrainBitmap(tileset, map, actualSize))
|
||||
return AddStaticResources(tileset, map, resourceRules, terrain);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
@@ -58,7 +57,7 @@ namespace OpenRA.Graphics
|
||||
var b = new Bitmap(Size, 1, PixelFormat.Format32bppArgb);
|
||||
var data = b.LockBits(new Rectangle(0, 0, b.Width, b.Height),
|
||||
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
|
||||
var temp = new uint[Size];
|
||||
var temp = new uint[Palette.Size];
|
||||
palette.CopyToArray(temp, 0);
|
||||
Marshal.Copy((int[])(object)temp, 0, data.Scan0, Size);
|
||||
b.UnlockBits(data);
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
public sealed class PaletteReference
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
@@ -30,7 +29,7 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
// Increase luminosity if required to represent the full ramp
|
||||
var rampRange = (byte)((1 - rampFraction) * c.L);
|
||||
var c1 = new HSLColor(c.H, c.S, Math.Max(rampRange, c.L)).RGB;
|
||||
var c1 = new HSLColor(c.H, c.S, (byte)Math.Max(rampRange, c.L)).RGB;
|
||||
var c2 = new HSLColor(c.H, c.S, (byte)Math.Max(0, c.L - rampRange)).RGB;
|
||||
var baseIndex = ramp[0];
|
||||
var remapRamp = ramp.Select(r => r - ramp[0]);
|
||||
|
||||
72
OpenRA.Game/Graphics/QuadRenderer.cs
Normal file
72
OpenRA.Game/Graphics/QuadRenderer.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2015 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 COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
public class QuadRenderer : Renderer.IBatchRenderer
|
||||
{
|
||||
readonly Renderer renderer;
|
||||
readonly IShader shader;
|
||||
readonly Action renderAction;
|
||||
|
||||
readonly Vertex[] vertices;
|
||||
int nv = 0;
|
||||
|
||||
public QuadRenderer(Renderer renderer, IShader shader)
|
||||
{
|
||||
this.renderer = renderer;
|
||||
this.shader = shader;
|
||||
vertices = new Vertex[renderer.TempBufferSize];
|
||||
renderAction = () => renderer.DrawBatch(vertices, nv, PrimitiveType.QuadList);
|
||||
}
|
||||
|
||||
public void Flush()
|
||||
{
|
||||
if (nv > 0)
|
||||
{
|
||||
renderer.Device.SetBlendMode(BlendMode.Alpha);
|
||||
shader.Render(renderAction);
|
||||
renderer.Device.SetBlendMode(BlendMode.None);
|
||||
|
||||
nv = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void FillRect(RectangleF rect, Color color)
|
||||
{
|
||||
renderer.CurrentBatchRenderer = this;
|
||||
|
||||
if (nv + 4 > renderer.TempBufferSize)
|
||||
Flush();
|
||||
|
||||
color = Util.PremultiplyAlpha(color);
|
||||
var r = color.R / 255.0f;
|
||||
var g = color.G / 255.0f;
|
||||
var b = color.B / 255.0f;
|
||||
var a = color.A / 255.0f;
|
||||
vertices[nv] = new Vertex(new float2(rect.Left, rect.Top), r, g, b, a);
|
||||
vertices[nv + 1] = new Vertex(new float2(rect.Right, rect.Top), r, g, b, a);
|
||||
vertices[nv + 2] = new Vertex(new float2(rect.Right, rect.Bottom), r, g, b, a);
|
||||
vertices[nv + 3] = new Vertex(new float2(rect.Left, rect.Bottom), r, g, b, a);
|
||||
|
||||
nv += 4;
|
||||
}
|
||||
|
||||
public void SetViewportParams(Size screen, float zoom, int2 scroll)
|
||||
{
|
||||
shader.SetVec("Scroll", scroll.X, scroll.Y);
|
||||
shader.SetVec("r1", zoom * 2f / screen.Width, -zoom * 2f / screen.Height);
|
||||
shader.SetVec("r2", -1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,16 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
|
||||
@@ -1,275 +0,0 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
public class RgbaColorRenderer : Renderer.IBatchRenderer
|
||||
{
|
||||
static readonly float2 Offset = new float2(0.5f, 0.5f);
|
||||
|
||||
readonly Renderer renderer;
|
||||
readonly IShader shader;
|
||||
readonly Action renderAction;
|
||||
|
||||
readonly Vertex[] vertices;
|
||||
int nv = 0;
|
||||
|
||||
public RgbaColorRenderer(Renderer renderer, IShader shader)
|
||||
{
|
||||
this.renderer = renderer;
|
||||
this.shader = shader;
|
||||
vertices = new Vertex[renderer.TempBufferSize];
|
||||
renderAction = () => renderer.DrawBatch(vertices, nv, PrimitiveType.TriangleList);
|
||||
}
|
||||
|
||||
public void Flush()
|
||||
{
|
||||
if (nv > 0)
|
||||
{
|
||||
renderer.Device.SetBlendMode(BlendMode.Alpha);
|
||||
shader.Render(renderAction);
|
||||
renderer.Device.SetBlendMode(BlendMode.None);
|
||||
|
||||
nv = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawLine(float2 start, float2 end, float width, Color startColor, Color endColor)
|
||||
{
|
||||
renderer.CurrentBatchRenderer = this;
|
||||
|
||||
if (nv + 6 > renderer.TempBufferSize)
|
||||
Flush();
|
||||
|
||||
var delta = (end - start) / (end - start).Length;
|
||||
var corner = width / 2 * new float2(-delta.Y, delta.X);
|
||||
|
||||
startColor = Util.PremultiplyAlpha(startColor);
|
||||
var sr = startColor.R / 255.0f;
|
||||
var sg = startColor.G / 255.0f;
|
||||
var sb = startColor.B / 255.0f;
|
||||
var sa = startColor.A / 255.0f;
|
||||
|
||||
endColor = Util.PremultiplyAlpha(endColor);
|
||||
var er = endColor.R / 255.0f;
|
||||
var eg = endColor.G / 255.0f;
|
||||
var eb = endColor.B / 255.0f;
|
||||
var ea = endColor.A / 255.0f;
|
||||
|
||||
vertices[nv++] = new Vertex(start - corner + Offset, sr, sg, sb, sa);
|
||||
vertices[nv++] = new Vertex(start + corner + Offset, sr, sg, sb, sa);
|
||||
vertices[nv++] = new Vertex(end + corner + Offset, er, eg, eb, ea);
|
||||
vertices[nv++] = new Vertex(end + corner + Offset, er, eg, eb, ea);
|
||||
vertices[nv++] = new Vertex(end - corner + Offset, er, eg, eb, ea);
|
||||
vertices[nv++] = new Vertex(start - corner + Offset, sr, sg, sb, sa);
|
||||
}
|
||||
|
||||
public void DrawLine(float2 start, float2 end, float width, Color color)
|
||||
{
|
||||
renderer.CurrentBatchRenderer = this;
|
||||
|
||||
if (nv + 6 > renderer.TempBufferSize)
|
||||
Flush();
|
||||
|
||||
var delta = (end - start) / (end - start).Length;
|
||||
var corner = width / 2 * new float2(-delta.Y, delta.X);
|
||||
|
||||
color = Util.PremultiplyAlpha(color);
|
||||
var r = color.R / 255.0f;
|
||||
var g = color.G / 255.0f;
|
||||
var b = color.B / 255.0f;
|
||||
var a = color.A / 255.0f;
|
||||
|
||||
vertices[nv++] = new Vertex(start - corner + Offset, r, g, b, a);
|
||||
vertices[nv++] = new Vertex(start + corner + Offset, r, g, b, a);
|
||||
vertices[nv++] = new Vertex(end + corner + Offset, r, g, b, a);
|
||||
vertices[nv++] = new Vertex(end + corner + Offset, r, g, b, a);
|
||||
vertices[nv++] = new Vertex(end - corner + Offset, r, g, b, a);
|
||||
vertices[nv++] = new Vertex(start - corner + Offset, r, g, b, a);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculate the intersection of two lines.
|
||||
/// Will behave badly if the lines are parallel
|
||||
/// </summary>
|
||||
float2 IntersectionOf(float2 a, float2 da, float2 b, float2 db)
|
||||
{
|
||||
var crossA = a.X * (a.Y + da.Y) - a.Y * (a.X + da.X);
|
||||
var crossB = b.X * (b.Y + db.Y) - b.Y * (b.X + db.X);
|
||||
var x = da.X * crossB - db.X * crossA;
|
||||
var y = da.Y * crossB - db.Y * crossA;
|
||||
var d = da.X * db.Y - da.Y * db.X;
|
||||
return new float2(x, y) / d;
|
||||
}
|
||||
|
||||
void DrawDisconnectedLine(IEnumerable<float2> points, float width, Color color)
|
||||
{
|
||||
using (var e = points.GetEnumerator())
|
||||
{
|
||||
if (!e.MoveNext())
|
||||
return;
|
||||
|
||||
var lastPoint = e.Current;
|
||||
while (e.MoveNext())
|
||||
{
|
||||
var point = e.Current;
|
||||
DrawLine(lastPoint, point, width, color);
|
||||
lastPoint = point;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrawConnectedLine(float2[] points, float width, Color color, bool closed)
|
||||
{
|
||||
// Not a line
|
||||
if (points.Length < 2)
|
||||
return;
|
||||
|
||||
// Single segment
|
||||
if (points.Length == 2)
|
||||
{
|
||||
DrawLine(points[0], points[1], width, color);
|
||||
return;
|
||||
}
|
||||
|
||||
renderer.CurrentBatchRenderer = this;
|
||||
color = Util.PremultiplyAlpha(color);
|
||||
var r = color.R / 255.0f;
|
||||
var g = color.G / 255.0f;
|
||||
var b = color.B / 255.0f;
|
||||
var a = color.A / 255.0f;
|
||||
|
||||
var start = points[0];
|
||||
var end = points[1];
|
||||
var dir = (end - start) / (end - start).Length;
|
||||
var corner = width / 2 * new float2(-dir.Y, dir.X);
|
||||
|
||||
// Corners for start of line segment
|
||||
var ca = start - corner;
|
||||
var cb = start + corner;
|
||||
|
||||
// Segment is part of closed loop
|
||||
if (closed)
|
||||
{
|
||||
var prev = points[points.Length - 1];
|
||||
var prevDir = (start - prev) / (start - prev).Length;
|
||||
var prevCorner = width / 2 * new float2(-prevDir.Y, prevDir.X);
|
||||
ca = IntersectionOf(start - prevCorner, prevDir, start - corner, dir);
|
||||
cb = IntersectionOf(start + prevCorner, prevDir, start + corner, dir);
|
||||
}
|
||||
|
||||
var limit = closed ? points.Length : points.Length - 1;
|
||||
for (var i = 0; i < limit; i++)
|
||||
{
|
||||
var next = points[(i + 2) % points.Length];
|
||||
var nextDir = (next - end) / (next - end).Length;
|
||||
var nextCorner = width / 2 * new float2(-nextDir.Y, nextDir.X);
|
||||
|
||||
// Vertices for the corners joining start-end to end-next
|
||||
var cc = closed || i < limit ? IntersectionOf(end + corner, dir, end + nextCorner, nextDir) : end + corner;
|
||||
var cd = closed || i < limit ? IntersectionOf(end - corner, dir, end - nextCorner, nextDir) : end - corner;
|
||||
|
||||
// Fill segment
|
||||
if (nv + 6 > renderer.TempBufferSize)
|
||||
Flush();
|
||||
|
||||
vertices[nv++] = new Vertex(ca + Offset, r, g, b, a);
|
||||
vertices[nv++] = new Vertex(cb + Offset, r, g, b, a);
|
||||
vertices[nv++] = new Vertex(cc + Offset, r, g, b, a);
|
||||
vertices[nv++] = new Vertex(cc + Offset, r, g, b, a);
|
||||
vertices[nv++] = new Vertex(cd + Offset, r, g, b, a);
|
||||
vertices[nv++] = new Vertex(ca + Offset, r, g, b, a);
|
||||
|
||||
// Advance line segment
|
||||
end = next;
|
||||
dir = nextDir;
|
||||
corner = nextCorner;
|
||||
|
||||
ca = cd;
|
||||
cb = cc;
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawLine(IEnumerable<float2> points, float width, Color color, bool connectSegments = false)
|
||||
{
|
||||
if (!connectSegments)
|
||||
DrawDisconnectedLine(points, width, color);
|
||||
else
|
||||
DrawConnectedLine(points as float2[] ?? points.ToArray(), width, color, false);
|
||||
}
|
||||
|
||||
public void DrawPolygon(float2[] vertices, float width, Color color)
|
||||
{
|
||||
DrawConnectedLine(vertices, width, color, true);
|
||||
}
|
||||
|
||||
public void DrawRect(float2 tl, float2 br, float width, Color color)
|
||||
{
|
||||
var tr = new float2(br.X, tl.Y);
|
||||
var bl = new float2(tl.X, br.Y);
|
||||
DrawPolygon(new[] { tl, tr, br, bl }, width, color);
|
||||
}
|
||||
|
||||
public void FillRect(float2 tl, float2 br, Color color)
|
||||
{
|
||||
var tr = new float2(br.X, tl.Y);
|
||||
var bl = new float2(tl.X, br.Y);
|
||||
FillRect(tl, tr, br, bl, color);
|
||||
}
|
||||
|
||||
public void FillRect(float2 a, float2 b, float2 c, float2 d, Color color)
|
||||
{
|
||||
renderer.CurrentBatchRenderer = this;
|
||||
|
||||
if (nv + 6 > renderer.TempBufferSize)
|
||||
Flush();
|
||||
|
||||
color = Util.PremultiplyAlpha(color);
|
||||
var cr = color.R / 255.0f;
|
||||
var cg = color.G / 255.0f;
|
||||
var cb = color.B / 255.0f;
|
||||
var ca = color.A / 255.0f;
|
||||
|
||||
vertices[nv++] = new Vertex(a + Offset, cr, cg, cb, ca);
|
||||
vertices[nv++] = new Vertex(b + Offset, cr, cg, cb, ca);
|
||||
vertices[nv++] = new Vertex(c + Offset, cr, cg, cb, ca);
|
||||
vertices[nv++] = new Vertex(c + Offset, cr, cg, cb, ca);
|
||||
vertices[nv++] = new Vertex(d + Offset, cr, cg, cb, ca);
|
||||
vertices[nv++] = new Vertex(a + Offset, cr, cg, cb, ca);
|
||||
}
|
||||
|
||||
public void FillEllipse(RectangleF r, Color color, int vertices = 32)
|
||||
{
|
||||
// TODO: Create an ellipse polygon instead
|
||||
var a = (r.Right - r.Left) / 2;
|
||||
var b = (r.Bottom - r.Top) / 2;
|
||||
var xc = (r.Right + r.Left) / 2;
|
||||
var yc = (r.Bottom + r.Top) / 2;
|
||||
for (var y = r.Top; y <= r.Bottom; y++)
|
||||
{
|
||||
var dx = a * (float)Math.Sqrt(1 - (y - yc) * (y - yc) / b / b);
|
||||
DrawLine(new float2(xc - dx, y), new float2(xc + dx, y), 1, color);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetViewportParams(Size screen, float zoom, int2 scroll)
|
||||
{
|
||||
shader.SetVec("Scroll", scroll.X, scroll.Y);
|
||||
shader.SetVec("r1", zoom * 2f / screen.Width, -zoom * 2f / screen.Height);
|
||||
shader.SetVec("r2", -1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Drawing;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
@@ -18,26 +18,17 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
readonly WPos pos;
|
||||
readonly Actor actor;
|
||||
readonly bool displayHealth;
|
||||
readonly bool displayExtra;
|
||||
|
||||
public SelectionBarsRenderable(Actor actor, bool displayHealth, bool displayExtra)
|
||||
: this(actor.CenterPosition, actor)
|
||||
{
|
||||
this.displayHealth = displayHealth;
|
||||
this.displayExtra = displayExtra;
|
||||
}
|
||||
public SelectionBarsRenderable(Actor actor)
|
||||
: this(actor.CenterPosition, actor) { }
|
||||
|
||||
public SelectionBarsRenderable(WPos pos, Actor actor)
|
||||
: this()
|
||||
{
|
||||
this.pos = pos;
|
||||
this.actor = actor;
|
||||
}
|
||||
|
||||
public WPos Pos { get { return pos; } }
|
||||
public bool DisplayHealth { get { return displayHealth; } }
|
||||
public bool DisplayExtra { get { return displayExtra; } }
|
||||
|
||||
public PaletteReference Palette { get { return null; } }
|
||||
public int ZOffset { get { return 0; } }
|
||||
@@ -64,30 +55,50 @@ namespace OpenRA.Graphics
|
||||
|
||||
void DrawSelectionBar(WorldRenderer wr, float2 start, float2 end, float value, Color barColor)
|
||||
{
|
||||
var iz = 1 / wr.Viewport.Zoom;
|
||||
var c = Color.FromArgb(128, 30, 30, 30);
|
||||
var c2 = Color.FromArgb(128, 10, 10, 10);
|
||||
var p = new float2(0, -4 * iz);
|
||||
var q = new float2(0, -3 * iz);
|
||||
var r = new float2(0, -2 * iz);
|
||||
var p = new float2(0, -4 / wr.Viewport.Zoom);
|
||||
var q = new float2(0, -3 / wr.Viewport.Zoom);
|
||||
var r = new float2(0, -2 / wr.Viewport.Zoom);
|
||||
|
||||
var barColor2 = Color.FromArgb(255, barColor.R / 2, barColor.G / 2, barColor.B / 2);
|
||||
|
||||
var z = float2.Lerp(start, end, value);
|
||||
var wcr = Game.Renderer.WorldRgbaColorRenderer;
|
||||
wcr.DrawLine(start + p, end + p, iz, c);
|
||||
wcr.DrawLine(start + q, end + q, iz, c2);
|
||||
wcr.DrawLine(start + r, end + r, iz, c);
|
||||
var wlr = Game.Renderer.WorldLineRenderer;
|
||||
wlr.DrawLine(start + p, end + p, c);
|
||||
wlr.DrawLine(start + q, end + q, c2);
|
||||
wlr.DrawLine(start + r, end + r, c);
|
||||
|
||||
wcr.DrawLine(start + p, z + p, iz, barColor2);
|
||||
wcr.DrawLine(start + q, z + q, iz, barColor);
|
||||
wcr.DrawLine(start + r, z + r, iz, barColor2);
|
||||
wlr.DrawLine(start + p, z + p, barColor2);
|
||||
wlr.DrawLine(start + q, z + q, barColor);
|
||||
wlr.DrawLine(start + r, z + r, barColor2);
|
||||
}
|
||||
|
||||
Color GetHealthColor(IHealth health)
|
||||
{
|
||||
if (Game.Settings.Game.UsePlayerStanceColors)
|
||||
return actor.Owner.PlayerStanceColor(actor);
|
||||
var player = actor.World.RenderPlayer ?? actor.World.LocalPlayer;
|
||||
|
||||
if (Game.Settings.Game.TeamHealthColors && player != null && !player.Spectating)
|
||||
{
|
||||
var apparentOwner = actor.EffectiveOwner != null && actor.EffectiveOwner.Disguised
|
||||
? actor.EffectiveOwner.Owner
|
||||
: actor.Owner;
|
||||
|
||||
// For friendly spies, treat the unit's owner as the actual owner
|
||||
if (actor.Owner.IsAlliedWith(actor.World.RenderPlayer))
|
||||
apparentOwner = actor.Owner;
|
||||
|
||||
if (apparentOwner == player)
|
||||
return Color.LimeGreen;
|
||||
|
||||
if (apparentOwner.IsAlliedWith(player))
|
||||
return Color.Yellow;
|
||||
|
||||
if (apparentOwner.NonCombatant)
|
||||
return Color.Tan;
|
||||
|
||||
return Color.Red;
|
||||
}
|
||||
else
|
||||
return health.DamageState == DamageState.Critical ? Color.Red :
|
||||
health.DamageState == DamageState.Heavy ? Color.Yellow : Color.LimeGreen;
|
||||
@@ -100,10 +111,9 @@ namespace OpenRA.Graphics
|
||||
|
||||
var c = Color.FromArgb(128, 30, 30, 30);
|
||||
var c2 = Color.FromArgb(128, 10, 10, 10);
|
||||
var iz = 1 / wr.Viewport.Zoom;
|
||||
var p = new float2(0, -4 * iz);
|
||||
var q = new float2(0, -3 * iz);
|
||||
var r = new float2(0, -2 * iz);
|
||||
var p = new float2(0, -4 / wr.Viewport.Zoom);
|
||||
var q = new float2(0, -3 / wr.Viewport.Zoom);
|
||||
var r = new float2(0, -2 / wr.Viewport.Zoom);
|
||||
|
||||
var healthColor = GetHealthColor(health);
|
||||
var healthColor2 = Color.FromArgb(
|
||||
@@ -114,14 +124,14 @@ namespace OpenRA.Graphics
|
||||
|
||||
var z = float2.Lerp(start, end, (float)health.HP / health.MaxHP);
|
||||
|
||||
var wcr = Game.Renderer.WorldRgbaColorRenderer;
|
||||
wcr.DrawLine(start + p, end + p, iz, c);
|
||||
wcr.DrawLine(start + q, end + q, iz, c2);
|
||||
wcr.DrawLine(start + r, end + r, iz, c);
|
||||
var wlr = Game.Renderer.WorldLineRenderer;
|
||||
wlr.DrawLine(start + p, end + p, c);
|
||||
wlr.DrawLine(start + q, end + q, c2);
|
||||
wlr.DrawLine(start + r, end + r, c);
|
||||
|
||||
wcr.DrawLine(start + p, z + p, iz, healthColor2);
|
||||
wcr.DrawLine(start + q, z + q, iz, healthColor);
|
||||
wcr.DrawLine(start + r, z + r, iz, healthColor2);
|
||||
wlr.DrawLine(start + p, z + p, healthColor2);
|
||||
wlr.DrawLine(start + q, z + q, healthColor);
|
||||
wlr.DrawLine(start + r, z + r, healthColor2);
|
||||
|
||||
if (health.DisplayHP != health.HP)
|
||||
{
|
||||
@@ -133,9 +143,9 @@ namespace OpenRA.Graphics
|
||||
deltaColor.B / 2);
|
||||
var zz = float2.Lerp(start, end, (float)health.DisplayHP / health.MaxHP);
|
||||
|
||||
wcr.DrawLine(z + p, zz + p, iz, deltaColor2);
|
||||
wcr.DrawLine(z + q, zz + q, iz, deltaColor);
|
||||
wcr.DrawLine(z + r, zz + r, iz, deltaColor2);
|
||||
wlr.DrawLine(z + p, zz + p, deltaColor2);
|
||||
wlr.DrawLine(z + q, zz + q, deltaColor);
|
||||
wlr.DrawLine(z + r, zz + r, deltaColor2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,11 +164,8 @@ namespace OpenRA.Graphics
|
||||
var start = new float2(bounds.Left + 1, bounds.Top);
|
||||
var end = new float2(bounds.Right - 1, bounds.Top);
|
||||
|
||||
if (DisplayHealth)
|
||||
DrawHealthBar(wr, health, start, end);
|
||||
|
||||
if (DisplayExtra)
|
||||
DrawExtraBars(wr, start, end);
|
||||
DrawHealthBar(wr, health, start, end);
|
||||
DrawExtraBars(wr, start, end);
|
||||
}
|
||||
|
||||
public void RenderDebugGeometry(WorldRenderer wr) { }
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using OpenRA.FileSystem;
|
||||
using System.Reflection;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
@@ -43,27 +43,15 @@ namespace OpenRA.Graphics
|
||||
IReadOnlyDictionary<string, ISpriteSequence> ParseSequences(ModData modData, TileSet tileSet, SpriteCache cache, MiniYamlNode node);
|
||||
}
|
||||
|
||||
public class SequenceProvider : IDisposable
|
||||
public class SequenceProvider
|
||||
{
|
||||
readonly ModData modData;
|
||||
readonly TileSet tileSet;
|
||||
readonly Lazy<Sequences> sequences;
|
||||
readonly Lazy<SpriteCache> spriteCache;
|
||||
public SpriteCache SpriteCache { get { return spriteCache.Value; } }
|
||||
public readonly SpriteCache SpriteCache;
|
||||
|
||||
readonly Dictionary<string, UnitSequences> sequenceCache = new Dictionary<string, UnitSequences>();
|
||||
|
||||
public SequenceProvider(IReadOnlyFileSystem fileSystem, ModData modData, TileSet tileSet, MiniYaml additionalSequences)
|
||||
public SequenceProvider(SequenceCache cache, Map map)
|
||||
{
|
||||
this.modData = modData;
|
||||
this.tileSet = tileSet;
|
||||
sequences = Exts.Lazy(() =>
|
||||
{
|
||||
using (new Support.PerfTimer("LoadSequences"))
|
||||
return Load(fileSystem, additionalSequences);
|
||||
});
|
||||
|
||||
spriteCache = Exts.Lazy(() => new SpriteCache(fileSystem, modData.SpriteLoaders, new SheetBuilder(SheetType.Indexed)));
|
||||
this.sequences = Exts.Lazy(() => cache.LoadSequences(map));
|
||||
this.SpriteCache = cache.SpriteCache;
|
||||
}
|
||||
|
||||
public ISpriteSequence GetSequence(string unitName, string sequenceName)
|
||||
@@ -102,9 +90,47 @@ namespace OpenRA.Graphics
|
||||
return unitSeq.Value.Keys;
|
||||
}
|
||||
|
||||
Sequences Load(IReadOnlyFileSystem fileSystem, MiniYaml additionalSequences)
|
||||
public void Preload()
|
||||
{
|
||||
var nodes = MiniYaml.Load(fileSystem, modData.Manifest.Sequences, additionalSequences);
|
||||
SpriteCache.SheetBuilder.Current.CreateBuffer();
|
||||
foreach (var unitSeq in sequences.Value.Values)
|
||||
foreach (var seq in unitSeq.Value.Values) { }
|
||||
SpriteCache.SheetBuilder.Current.ReleaseBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class SequenceCache : IDisposable
|
||||
{
|
||||
readonly ModData modData;
|
||||
readonly TileSet tileSet;
|
||||
readonly Lazy<SpriteCache> spriteCache;
|
||||
public SpriteCache SpriteCache { get { return spriteCache.Value; } }
|
||||
|
||||
readonly Dictionary<string, UnitSequences> sequenceCache = new Dictionary<string, UnitSequences>();
|
||||
|
||||
public SequenceCache(ModData modData, TileSet tileSet)
|
||||
{
|
||||
this.modData = modData;
|
||||
this.tileSet = tileSet;
|
||||
|
||||
// Every time we load a tile set, we create a sequence cache for it
|
||||
spriteCache = Exts.Lazy(() => new SpriteCache(modData.SpriteLoaders, new SheetBuilder(SheetType.Indexed)));
|
||||
}
|
||||
|
||||
public Sequences LoadSequences(Map map)
|
||||
{
|
||||
using (new Support.PerfTimer("LoadSequences"))
|
||||
return Load(map != null ? map.SequenceDefinitions : new List<MiniYamlNode>());
|
||||
}
|
||||
|
||||
Sequences Load(List<MiniYamlNode> sequenceNodes)
|
||||
{
|
||||
var sequenceFiles = modData.Manifest.Sequences;
|
||||
|
||||
var nodes = sequenceFiles
|
||||
.Select(s => MiniYaml.FromFile(s))
|
||||
.Aggregate(sequenceNodes, MiniYaml.MergeLiberal);
|
||||
|
||||
var items = new Dictionary<string, UnitSequences>();
|
||||
foreach (var n in nodes)
|
||||
{
|
||||
@@ -127,14 +153,6 @@ namespace OpenRA.Graphics
|
||||
return new ReadOnlyDictionary<string, UnitSequences>(items);
|
||||
}
|
||||
|
||||
public void Preload()
|
||||
{
|
||||
SpriteCache.SheetBuilder.Current.CreateBuffer();
|
||||
foreach (var unitSeq in sequences.Value.Values)
|
||||
foreach (var seq in unitSeq.Value.Values) { }
|
||||
SpriteCache.SheetBuilder.Current.ReleaseBuffer();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (spriteCache.IsValueCreated)
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using OpenRA.FileSystem;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
@@ -48,8 +47,9 @@ namespace OpenRA.Graphics
|
||||
Size = texture.Size;
|
||||
}
|
||||
|
||||
public Sheet(SheetType type, Stream stream)
|
||||
public Sheet(SheetType type, string filename)
|
||||
{
|
||||
using (var stream = GlobalFileSystem.Open(filename))
|
||||
using (var bitmap = (Bitmap)Image.FromStream(stream))
|
||||
{
|
||||
Size = bitmap.Size;
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
|
||||
@@ -10,7 +10,9 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Primitives;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
@@ -22,7 +24,7 @@ namespace OpenRA.Graphics
|
||||
void Tick();
|
||||
}
|
||||
|
||||
public sealed class SoftwareCursor : ICursor
|
||||
public class SoftwareCursor : ICursor
|
||||
{
|
||||
readonly HardwarePalette palette = new HardwarePalette();
|
||||
readonly Cache<string, PaletteReference> paletteReferences;
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
@@ -18,7 +17,7 @@ using SharpFont;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
public sealed class SpriteFont : IDisposable
|
||||
public class SpriteFont
|
||||
{
|
||||
static readonly Library Library = new Library();
|
||||
|
||||
@@ -28,7 +27,7 @@ namespace OpenRA.Graphics
|
||||
readonly Face face;
|
||||
readonly Cache<Pair<char, Color>, GlyphInfo> glyphs;
|
||||
|
||||
public SpriteFont(string name, byte[] data, int size, SheetBuilder builder)
|
||||
public SpriteFont(string name, int size, SheetBuilder builder)
|
||||
{
|
||||
if (builder.Type != SheetType.BGRA)
|
||||
throw new ArgumentException("The sheet builder must create BGRA sheets.", "builder");
|
||||
@@ -36,12 +35,11 @@ namespace OpenRA.Graphics
|
||||
this.size = size;
|
||||
this.builder = builder;
|
||||
|
||||
face = new Face(Library, data, 0);
|
||||
face = new Face(Library, name);
|
||||
face.SetPixelSizes((uint)size, (uint)size);
|
||||
|
||||
glyphs = new Cache<Pair<char, Color>, GlyphInfo>(CreateGlyph, Pair<char, Color>.EqualityComparer);
|
||||
|
||||
// PERF: Cache these delegates for Measure calls.
|
||||
Func<char, float> characterWidth = character => glyphs[Pair.New(character, Color.White)].Advance;
|
||||
lineWidth = line => line.Sum(characterWidth);
|
||||
|
||||
@@ -151,11 +149,6 @@ namespace OpenRA.Graphics
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
face.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
class GlyphInfo
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
@@ -24,17 +23,8 @@ namespace OpenRA.Graphics
|
||||
|
||||
public interface ISpriteFrame
|
||||
{
|
||||
/// <summary>
|
||||
/// Size of the frame's `Data`.
|
||||
/// </summary>
|
||||
Size Size { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of the entire frame including the frame's `Size`.
|
||||
/// Think of this like a picture frame.
|
||||
/// </summary>
|
||||
Size FrameSize { get; }
|
||||
|
||||
float2 Offset { get; }
|
||||
byte[] Data { get; }
|
||||
bool DisableExportPadding { get; }
|
||||
@@ -45,11 +35,11 @@ namespace OpenRA.Graphics
|
||||
public readonly SheetBuilder SheetBuilder;
|
||||
readonly Cache<string, Sprite[]> sprites;
|
||||
|
||||
public SpriteCache(IReadOnlyFileSystem fileSystem, ISpriteLoader[] loaders, SheetBuilder sheetBuilder)
|
||||
public SpriteCache(ISpriteLoader[] loaders, SheetBuilder sheetBuilder)
|
||||
{
|
||||
SheetBuilder = sheetBuilder;
|
||||
|
||||
sprites = new Cache<string, Sprite[]>(filename => SpriteLoader.GetSprites(fileSystem, filename, loaders, sheetBuilder));
|
||||
sprites = new Cache<string, Sprite[]>(filename => SpriteLoader.GetSprites(filename, loaders, sheetBuilder));
|
||||
}
|
||||
|
||||
public Sprite[] this[string filename] { get { return sprites[filename]; } }
|
||||
@@ -59,9 +49,9 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
readonly Cache<string, ISpriteFrame[]> frames;
|
||||
|
||||
public FrameCache(IReadOnlyFileSystem fileSystem, ISpriteLoader[] loaders)
|
||||
public FrameCache(ISpriteLoader[] loaders)
|
||||
{
|
||||
frames = new Cache<string, ISpriteFrame[]>(filename => SpriteLoader.GetFrames(fileSystem, filename, loaders));
|
||||
frames = new Cache<string, ISpriteFrame[]>(filename => SpriteLoader.GetFrames(filename, loaders));
|
||||
}
|
||||
|
||||
public ISpriteFrame[] this[string filename] { get { return frames[filename]; } }
|
||||
@@ -69,31 +59,22 @@ namespace OpenRA.Graphics
|
||||
|
||||
public static class SpriteLoader
|
||||
{
|
||||
public static Sprite[] GetSprites(IReadOnlyFileSystem fileSystem, string filename, ISpriteLoader[] loaders, SheetBuilder sheetBuilder)
|
||||
public static Sprite[] GetSprites(string filename, ISpriteLoader[] loaders, SheetBuilder sheetBuilder)
|
||||
{
|
||||
return GetFrames(fileSystem, filename, loaders).Select(a => sheetBuilder.Add(a)).ToArray();
|
||||
return GetFrames(filename, loaders).Select(a => sheetBuilder.Add(a)).ToArray();
|
||||
}
|
||||
|
||||
public static ISpriteFrame[] GetFrames(IReadOnlyFileSystem fileSystem, string filename, ISpriteLoader[] loaders)
|
||||
public static ISpriteFrame[] GetFrames(string filename, ISpriteLoader[] loaders)
|
||||
{
|
||||
using (var stream = fileSystem.Open(filename))
|
||||
using (var stream = GlobalFileSystem.Open(filename))
|
||||
{
|
||||
var spriteFrames = GetFrames(stream, loaders);
|
||||
if (spriteFrames == null)
|
||||
throw new InvalidDataException(filename + " is not a valid sprite file!");
|
||||
ISpriteFrame[] frames;
|
||||
foreach (var loader in loaders)
|
||||
if (loader.TryParseSprite(stream, out frames))
|
||||
return frames;
|
||||
|
||||
return spriteFrames;
|
||||
throw new InvalidDataException(filename + " is not a valid sprite file");
|
||||
}
|
||||
}
|
||||
|
||||
public static ISpriteFrame[] GetFrames(Stream stream, ISpriteLoader[] loaders)
|
||||
{
|
||||
ISpriteFrame[] frames;
|
||||
foreach (var loader in loaders)
|
||||
if (loader.TryParseSprite(stream, out frames))
|
||||
return frames;
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
@@ -63,7 +62,7 @@ namespace OpenRA.Graphics
|
||||
public void RenderDebugGeometry(WorldRenderer wr)
|
||||
{
|
||||
var offset = ScreenPosition(wr) + sprite.Offset;
|
||||
Game.Renderer.WorldRgbaColorRenderer.DrawRect(offset, offset + sprite.Size, 1 / wr.Viewport.Zoom, Color.Red);
|
||||
Game.Renderer.WorldLineRenderer.DrawRect(offset, offset + sprite.Size, Color.Red);
|
||||
}
|
||||
|
||||
public Rectangle ScreenBounds(WorldRenderer wr)
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
@@ -30,7 +29,7 @@ namespace OpenRA.Graphics
|
||||
this.renderer = renderer;
|
||||
this.shader = shader;
|
||||
vertices = new Vertex[renderer.TempBufferSize];
|
||||
renderAction = () => renderer.DrawBatch(vertices, nv, PrimitiveType.TriangleList);
|
||||
renderAction = () => renderer.DrawBatch(vertices, nv, PrimitiveType.QuadList);
|
||||
}
|
||||
|
||||
public void Flush()
|
||||
@@ -52,7 +51,7 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
renderer.CurrentBatchRenderer = this;
|
||||
|
||||
if (s.BlendMode != currentBlend || s.Sheet != currentSheet || nv + 6 > renderer.TempBufferSize)
|
||||
if (s.BlendMode != currentBlend || s.Sheet != currentSheet || nv + 4 > renderer.TempBufferSize)
|
||||
Flush();
|
||||
|
||||
currentBlend = s.BlendMode;
|
||||
@@ -73,7 +72,7 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
SetRenderStateForSprite(s);
|
||||
Util.FastCreateQuad(vertices, location + s.FractionalOffset * size, s, paletteTextureIndex, nv, size);
|
||||
nv += 6;
|
||||
nv += 4;
|
||||
}
|
||||
|
||||
// For RGBASpriteRenderer, which doesn't use palettes
|
||||
@@ -91,14 +90,14 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
SetRenderStateForSprite(s);
|
||||
Util.FastCreateQuad(vertices, a, b, c, d, s, 0, nv);
|
||||
nv += 6;
|
||||
nv += 4;
|
||||
}
|
||||
|
||||
public void DrawSprite(Sprite s, Vertex[] sourceVertices, int offset)
|
||||
{
|
||||
SetRenderStateForSprite(s);
|
||||
Array.Copy(sourceVertices, offset, vertices, nv, 6);
|
||||
nv += 6;
|
||||
Array.Copy(sourceVertices, offset, vertices, nv, 4);
|
||||
nv += 4;
|
||||
}
|
||||
|
||||
public void DrawVertexBuffer(IVertexBuffer<Vertex> buffer, int start, int length, PrimitiveType type, Sheet sheet, BlendMode blendMode)
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
@@ -42,26 +43,16 @@ namespace OpenRA.Graphics
|
||||
if (!waypoints.Any())
|
||||
return;
|
||||
|
||||
var iz = 1 / wr.Viewport.Zoom;
|
||||
var first = wr.ScreenPxPosition(waypoints.First());
|
||||
var a = first;
|
||||
foreach (var b in waypoints.Skip(1).Select(pos => wr.ScreenPxPosition(pos)))
|
||||
{
|
||||
Game.Renderer.WorldRgbaColorRenderer.DrawLine(a, b, iz, color);
|
||||
DrawTargetMarker(wr, color, b);
|
||||
Game.Renderer.WorldLineRenderer.DrawLine(a, b, color);
|
||||
wr.DrawTargetMarker(color, b);
|
||||
a = b;
|
||||
}
|
||||
|
||||
DrawTargetMarker(wr, color, first);
|
||||
}
|
||||
|
||||
public static void DrawTargetMarker(WorldRenderer wr, Color color, float2 location)
|
||||
{
|
||||
var iz = 1 / wr.Viewport.Zoom;
|
||||
var offset = new float2(iz, iz);
|
||||
var tl = location - offset;
|
||||
var br = location + offset;
|
||||
Game.Renderer.WorldRgbaColorRenderer.FillRect(tl, br, color);
|
||||
wr.DrawTargetMarker(color, first);
|
||||
}
|
||||
|
||||
public void RenderDebugGeometry(WorldRenderer wr) { }
|
||||
|
||||
@@ -1,73 +1,58 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
sealed class TerrainRenderer : IDisposable
|
||||
{
|
||||
readonly Map map;
|
||||
readonly Dictionary<string, TerrainSpriteLayer> spriteLayers = new Dictionary<string, TerrainSpriteLayer>();
|
||||
readonly TerrainSpriteLayer terrain;
|
||||
readonly Theater theater;
|
||||
readonly CellLayer<TerrainTile> mapTiles;
|
||||
readonly CellLayer<byte> mapHeight;
|
||||
|
||||
public TerrainRenderer(World world, WorldRenderer wr)
|
||||
{
|
||||
map = world.Map;
|
||||
theater = wr.Theater;
|
||||
mapTiles = world.Map.MapTiles.Value;
|
||||
mapHeight = world.Map.MapHeight.Value;
|
||||
|
||||
foreach (var template in map.Rules.TileSet.Templates)
|
||||
{
|
||||
var palette = template.Value.Palette ?? TileSet.TerrainPaletteInternalName;
|
||||
spriteLayers.GetOrAdd(palette, pal =>
|
||||
new TerrainSpriteLayer(world, wr, theater.Sheet, BlendMode.Alpha, wr.Palette(palette), world.Type != WorldType.Editor));
|
||||
}
|
||||
terrain = new TerrainSpriteLayer(world, wr, theater.Sheet, BlendMode.Alpha,
|
||||
wr.Palette("terrain"), wr.World.Type != WorldType.Editor);
|
||||
|
||||
foreach (var cell in map.AllCells)
|
||||
foreach (var cell in world.Map.AllCells)
|
||||
UpdateCell(cell);
|
||||
|
||||
map.Tiles.CellEntryChanged += UpdateCell;
|
||||
map.Height.CellEntryChanged += UpdateCell;
|
||||
mapTiles.CellEntryChanged += UpdateCell;
|
||||
mapHeight.CellEntryChanged += UpdateCell;
|
||||
}
|
||||
|
||||
public void UpdateCell(CPos cell)
|
||||
{
|
||||
var tile = map.Tiles[cell];
|
||||
var palette = TileSet.TerrainPaletteInternalName;
|
||||
if (map.Rules.TileSet.Templates.ContainsKey(tile.Type))
|
||||
palette = map.Rules.TileSet.Templates[tile.Type].Palette ?? palette;
|
||||
|
||||
var sprite = theater.TileSprite(tile);
|
||||
foreach (var kv in spriteLayers)
|
||||
kv.Value.Update(cell, palette == kv.Key ? sprite : null);
|
||||
terrain.Update(cell, theater.TileSprite(mapTiles[cell]));
|
||||
}
|
||||
|
||||
public void Draw(WorldRenderer wr, Viewport viewport)
|
||||
{
|
||||
foreach (var kv in spriteLayers.Values)
|
||||
kv.Draw(wr.Viewport);
|
||||
|
||||
terrain.Draw(viewport);
|
||||
foreach (var r in wr.World.WorldActor.TraitsImplementing<IRenderOverlay>())
|
||||
r.Render(wr);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
map.Tiles.CellEntryChanged -= UpdateCell;
|
||||
map.Height.CellEntryChanged -= UpdateCell;
|
||||
|
||||
foreach (var kv in spriteLayers.Values)
|
||||
kv.Dispose();
|
||||
mapTiles.CellEntryChanged -= UpdateCell;
|
||||
mapHeight.CellEntryChanged -= UpdateCell;
|
||||
terrain.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
@@ -13,6 +12,8 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
@@ -43,7 +44,7 @@ namespace OpenRA.Graphics
|
||||
this.palette = palette;
|
||||
|
||||
map = world.Map;
|
||||
rowStride = 6 * map.MapSize.X;
|
||||
rowStride = 4 * map.MapSize.X;
|
||||
|
||||
vertices = new Vertex[rowStride * map.MapSize.Y];
|
||||
vertexBuffer = Game.Renderer.Device.CreateVertexBuffer(vertices.Length);
|
||||
@@ -86,7 +87,7 @@ namespace OpenRA.Graphics
|
||||
else
|
||||
sprite = emptySprite;
|
||||
|
||||
var offset = rowStride * uv.V + 6 * uv.U;
|
||||
var offset = rowStride * uv.V + 4 * uv.U;
|
||||
Util.FastCreateQuad(vertices, pos, sprite, palette.TextureIndex, offset, sprite.Size);
|
||||
|
||||
dirtyRows.Add(uv.V);
|
||||
@@ -122,7 +123,7 @@ namespace OpenRA.Graphics
|
||||
|
||||
Game.Renderer.WorldSpriteRenderer.DrawVertexBuffer(
|
||||
vertexBuffer, rowStride * firstRow, rowStride * (lastRow - firstRow),
|
||||
PrimitiveType.TriangleList, Sheet, BlendMode);
|
||||
PrimitiveType.QuadList, Sheet, BlendMode);
|
||||
|
||||
Game.Renderer.Flush();
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
@@ -13,6 +12,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.FileSystem;
|
||||
using OpenRA.Support;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
@@ -57,7 +57,7 @@ namespace OpenRA.Graphics
|
||||
sheetBuilder = new SheetBuilder(type, allocate);
|
||||
random = new MersenneTwister();
|
||||
|
||||
var frameCache = new FrameCache(Game.ModData.DefaultFileSystem, Game.ModData.SpriteLoaders);
|
||||
var frameCache = new FrameCache(Game.ModData.SpriteLoaders);
|
||||
foreach (var t in tileset.Templates)
|
||||
{
|
||||
var variants = new List<Sprite[]>();
|
||||
|
||||
@@ -1,31 +1,30 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2015 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
public struct UISpriteRenderable : IRenderable, IFinalizedRenderable
|
||||
{
|
||||
readonly Sprite sprite;
|
||||
readonly WPos effectiveWorldPos;
|
||||
readonly int2 screenPos;
|
||||
readonly int zOffset;
|
||||
readonly PaletteReference palette;
|
||||
readonly float scale;
|
||||
|
||||
public UISpriteRenderable(Sprite sprite, WPos effectiveWorldPos, int2 screenPos, int zOffset, PaletteReference palette, float scale)
|
||||
public UISpriteRenderable(Sprite sprite, int2 screenPos, int zOffset, PaletteReference palette, float scale)
|
||||
{
|
||||
this.sprite = sprite;
|
||||
this.effectiveWorldPos = effectiveWorldPos;
|
||||
this.screenPos = screenPos;
|
||||
this.zOffset = zOffset;
|
||||
this.palette = palette;
|
||||
@@ -33,14 +32,14 @@ namespace OpenRA.Graphics
|
||||
}
|
||||
|
||||
// Does not exist in the world, so a world positions don't make sense
|
||||
public WPos Pos { get { return effectiveWorldPos; } }
|
||||
public WPos Pos { get { return WPos.Zero; } }
|
||||
public WVec Offset { get { return WVec.Zero; } }
|
||||
public bool IsDecoration { get { return true; } }
|
||||
|
||||
public PaletteReference Palette { get { return palette; } }
|
||||
public int ZOffset { get { return zOffset; } }
|
||||
|
||||
public IRenderable WithPalette(PaletteReference newPalette) { return new UISpriteRenderable(sprite, effectiveWorldPos, screenPos, zOffset, newPalette, scale); }
|
||||
public IRenderable WithPalette(PaletteReference newPalette) { return new UISpriteRenderable(sprite, screenPos, zOffset, newPalette, scale); }
|
||||
public IRenderable WithZOffset(int newOffset) { return this; }
|
||||
public IRenderable OffsetBy(WVec vec) { return this; }
|
||||
public IRenderable AsDecoration() { return this; }
|
||||
@@ -54,7 +53,7 @@ namespace OpenRA.Graphics
|
||||
public void RenderDebugGeometry(WorldRenderer wr)
|
||||
{
|
||||
var offset = screenPos + sprite.Offset;
|
||||
Game.Renderer.RgbaColorRenderer.DrawRect(offset, offset + sprite.Size, 1, Color.Red);
|
||||
Game.Renderer.LineRenderer.DrawRect(offset, offset + sprite.Size, Color.Red);
|
||||
}
|
||||
|
||||
public Rectangle ScreenBounds(WorldRenderer wr)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user