Warcraft II Forum

Warcraft II => Mods & Development => Topic started by: Lambchops on October 31, 2016, 08:27:45 PM

Title: Nerd's Corner
Post by: Lambchops on October 31, 2016, 08:27:45 PM
I found a bit of writing I did about NAT a while back. There's been some talk about this recently, so I modded it a little bit to make it more relevant to WC2, as I thought the more nerdy folks out there might find it helpful.

So NAT. What's it all about?

Lamby's super-abridged, mostly fictional, oversimplified, heavily biased synopsis: Network Address Translation is a messy, stop-gap measure that got dreamed up by psychotic, sadistic and under-medicated network engineer as a way to get more flexibility out of the already overcrowded IPV4 address space prior to the implementation of IPV6.

Most people know by now that IPV4 – that’s the 4 numbers with the dots in-between that we all recognise as an IP address - was just too small. There just wasn't enough numbers. Its a 32 bit value. 2^32 = just under 4.3 billion possible addresses. Seemed like a big number 50 years ago, but even 20 years ago people were realising there weren't enough to go around.

IPV6 has now been implemented, which has lots of address space - like crazy lots =). We still see IPV4 addresses on the surface, but the backbone of the internet is now all IPV6, and all those things like credit-card gobbling parking meters that all need their own address just have IPV6 addresses. IPV4 is still around to interface with all the existing technology.

So IPV4 addresses were just not cutting it – it's 4 measly bytes, and that limit was (and for the most part still is) hard coded into every bit of network infrastructure in the world. But! Thought the madman, most of the traffic is TCP and UDP, and they have this port number. It's another 2 bytes! What can we do with that? NOTHING you maniac, it already has an important function, leave it alone. But no…. We get Network Address Translation, and we'll probably be stuck with it until the end of days. Post nuclear holocaust the only things to survive will be cockroaches and NAT.

So yes, a port number is 16 bits (0 thru 65535) and only a fraction of them are actually used. Officially ports 0-1023 are 'system ports' and stuff above that can be registered by people who want to put their official stamp on them….. or you can just pick one that's not getting used too much ;) Wikipedia lists around 1300, including 3 entries for port 6112:

Code: [Select]
6112 TCP UDP dtspcd, execute commands and launch applications remotely,  Official
6112 TCP     Blizzard's Battle.net gaming service and some games, ArenaNet gaming service, Relic gaming service,  Unofficial
6112 TCP     Club Penguin Disney online game for kids,  Unofficial


Anyone spot the mistake? … battle.net port 6112 listed as TCP only. (nvm, I already fixed it – the guy maintaining the page sent me a rather curt little message about 'original research', but he left it because he knew I was right;)

So how many possible port numbers do we need? Well I think we can safely say its more than 256 (1 byte) and less than (256x256) 2 bytes, so allowing 2 bytes is about right. But how many port numbers are actually used every day? Depends who you ask… let's see well 53 is DNS, that’s a cert, and 80:HTTP, more to the point these days 443:HTTPS, 20-21:FTP maybe not daily, 37:TIME gets used behind the scenes, 25:SMTP (email) used lots, but not so much from home any more, these days its all secure web pages (443) and poor old 110:POP3 is well on the way out. I could go on,  hey I love that Doom still officially owns port 666, (a system port 8P) but in reality most of the traffic in an average network on an average day probably uses maybe 50 ports? Who knows, maybe 100? Ok so lets say, for the sake of argument, its 100…. but we have 65535 possible port numbers, so lets go ahead and divide that by 100 and now we can support a network of 655 individual nodes off a single IPV4 address.

How do we do this? Well we just have to introduce an agent at the crossover point between our NAT network and the real world.

The following description is, of course, complete and total rubbish for so many reasons… there are different types of NAT and different ways to implement things within them, and I'm no expert. This is just here to hopefully help people who know nothing at all about the subject to get their head around the general concept.

Think of it like a (crazy) guy with a clipboard who writes really fast and looks at every packet that goes past. First he sees an outbound packet from puter 20 on port 3000, he says “call it 10” and writes down 10 = 20:3000, then he changes the source port number to 10 and sends the packet on its way. Next there's an outbound packet from puter 44 on port 8008, so he writes down '11= 44:8008', changes the source port number to 11 and sends it on its way. Next there's a packet from puter 150 on port 3000…. '12 = 150:3000' …. off you go… he does this a lot.

The packets, with their re-assigned port numbers go to wherever they were going and (as is the nature of things) they get responses from remote computers somewhere in the world. Those computers do whatever they do with the payload – the chunk of data that this addressing system is carrying – then they send back their response. There's to and from IP addresses and a source port and a destination port. The remote computers received the packet on the destination port, and you guessed it, for the return journey its all switched around: the to address becomes the from address and vice-versa, and the source port becomes the destination port etc., and the return packets get sent back to the addresses that the initial packets were received from.

The thing is here, that as far as the remote computers are concerned, these packets all came from the same computer, because they were all using the same external IP address as the from address, so they all arrive back at the same place and are greeted by the loony with the clipboard who looks at the packets, then checks his clipboard and says “hmm, port 10… that's puter 20, port 3000”, so he changes the destination port to 3000 and the to address to puter 10's local IP address and sends it on its way.. etc. When he gets the port 12 return he sends that to puter 150, port 3000.

So 2 different computers on the local network have simultaneously requested data over port 3000 from 2 separate remote servers using the same external IP address and both receive their replies, on the same port, and are none the wiser that for most of the journey their packets actually had completely different addresses and ports on them. Likewise the remote server has no idea that the originating computer is not receiving the packets on port 10 or 12, but on port 3000. But because of the way NAT works it never matters because the nutter in the middle keeps untangling his own knots on the way back.

Why do it this way? When you think about the amount of data that is sent around just for one Game of Thrones episode, its colossal compared with this tiny little 2-byte port number… so why mess with it? There is, of course, a very good reason. It's because every piece of data in every layer of every packet is ordered according to some protocol or other, and somewhere along the line, some computer is going to process that data. So if you add data, or introduce some new protocol, it means the computer at the other end has to understand that change and correctly process it, or even just know to ignore it (Unless you're meta-tagging an mp3, which is just deliciously naughty – but that's another story;). NAT works by sneakily messing with the existing data so that the remote computers just process it in according to their existing protocols without having to be aware that any translation is taking place. In this way it can be introduced in a single location, to suit local purposes without having to upgrade the entire internet (which wasn't in the budget that quarter).

Well. That sound's really clever… so what's wrong with that? Well…. nothing …. and everything. Hmm, how to explain…

You know when you have to move house? You pack everything into boxes and it gets loaded onto a moving van, then unloaded at the other end and you try to reconstruct your home. To make this a bit easier, you no doubt write “kitchen” or “garage” on the boxes, maybe even “kitchen – glassware” and “kitchen – plastics”. This way you have an idea about where everything goes when you get to your new home. Also the guys from the moving company might even notice that a box says “glassware” and decide not drop it 8 feet off the back of the van onto the road with the rest of them (maybe?). Good idea.

  - - >  So your address is where your new house is, and the extra note about what the box is being used to move, and exactly where in the new house it needs to go when it arrives, can be thought of as the port number. < - -

So now what if 500 people are all moving interstate on the same day, and they are all using the same moving company? Bit of a worry.. ok then, let's up the ante a bit more... What if there was a little snafu and instead of printing address labels for 500 different addresses somebody printed 10,000 labels all with the same address on it and for whatever reason they had to use those labels, and the only place to write any notes on the boxes is in the one little space provided on the address label and that note space just is not big enough to write the correct address? How can this work? Well, says the madman with the clipboard. It seems everyone is writing “kitchen” on these things, hey I've got an idea! There's lots more words than just that…

How about if I write “unicycle” on this, that means “bathroom at the Jones house”, but if I label it “golf balls”, that means “kitchen at the Smith house”, and if I put down “proverb” that means garage at the Bloggs house. Then I can just keep a list here on my clipboard, and when when we get to the next state we can just look at the list and send everything where it needs to go.

As insanity would have it, it turns out this guy really is obsessive-compulsive enough to do this and he correctly decodes the labels on 10,000 boxes and sends them to the right house. He even crosses out “golf balls” and re-writes “kitchen” so Mrs. Smith knows where to take her (broken) glassware. Pretty neat trick right? Perhaps, at least until you have to cross some border where there's a security check, and the customs agent decides to check out your unicycle and discovers instead, bottles of shampoo and other liquid product, which we all know is what terrorists use to blow up planes so… oh dear… Mr. Customs agent rather ominously snaps on a rubber glove and asks you to step into a small cubicle…. and Mrs. Jones never does get her hand sanitizer back.

There are some important protocols that include some form of auditing of their own packets, the most obvious being IPsec or “Internet Protocol Security”. IPsec encrypts packets at the internet layer, which of course includes the port data which exists at the transport layer, so if NAT changes what it assumes is the source port number the packet has been corrupted and can't be decrypted.

The real problem is that the crazy-guy is messing with the language that everybody speaks. Nowhere in the universe, apart from in his twisted head, does “unicycle” mean “shampoo”. Its all well and good for stuff that he handles first, but when Mrs. Jones' mother tries to send them a pot-plant as a house-warming gift, the crazy guy re-labels it 'special fried rice' and sends it to Alaska.

And this is the problem with NAT for WC2. Battle.net is NOT a gaming server for WC2 games, its more like Craiglist. It just advertises the games. Initially the host's computer is the server, then it's mostly just peer-to-peer. The 'server' (BNet, PvPGN etc.) just relays messages and keeps track of the stats when the game ends. But, the other clients aren't replying to packets that the fruit-bat has already messed with, they are using the actual correct information that was posted in the game list, or supplied by the game host. So when a packet arrives at the NAT agent labeled “WC2 Game”, our friend looks at his clipboard and says, “oh, you're a medium sized flock of migrating geese” and points it towards the equator.



NAT is an IPV4 thing only. There is no IPV6 Network address translation, its just not needed, and here's why:


The IPV6 address space contains approximately:       
340,282,366,920,938,463,463,374,607,430,000,000,000 addresses.

The zeros on the end round it off to the nearest 10 billion addresses.
The entire IPV4 address space is under 4.3 billion addresses.

Assigning a trillion trillion IPV6 addresses to every person on the planet would account for less than 0.01% of the address space. Pretty sure nobody wanted to have to upgrade the internet again.

An IPV6 address uses the same amount of bandwidth as writing BOOBIES!
…… Damn I love numbers (and boobies :P)

Title: Re: Nerd's Corner
Post by: Yamon on November 02, 2016, 01:02:36 PM
http://www.youtube.com/watch?v=JCK0HmfZI74 (http://www.youtube.com/watch?v=JCK0HmfZI74)
Title: Re: Nerd's Corner
Post by: Lambchops on November 12, 2016, 11:34:07 AM
http://www.youtube.com/watch?v=JEGgUTVsl7k (http://www.youtube.com/watch?v=JEGgUTVsl7k)
Title: Re: Nerd's Corner
Post by: shesycompany on November 12, 2016, 11:58:23 AM
lol the last one ;D
Title: Re: Nerd's Corner
Post by: shesycompany on November 16, 2016, 06:32:22 PM
lamb your needed in the support section<
Title: Re: Nerd's Corner
Post by: shesycompany on December 04, 2016, 10:24:21 AM
(http://i67.tinypic.com/5koza1.jpg)

using free netzero over the weekend,had to have some tunes!

keepvid.com copy "video" shortcut,paste in this site,http://www.online-convert.com

put your bitrate etc,walla!!! hi speed 56k :P sounded pretty dam good on my 200mhz lappy, "put all my external modems up some where and lost :("

4 min oukast ms jackson at <1/4th 56k.

yeah it plays war2.ru its a beast! also suprised internet5.5 went to these sites :o

 :o video isnt that bad with mp4 sadly old procs cant handle it to well.

so theres a nerd bulletin post (bored out the ass :P)
Title: Re: Nerd's Corner
Post by: RipE[Eur0] on December 04, 2016, 04:50:14 PM
[url]http://www.youtube.com/watch?v=JEGgUTVsl7k[/url] ([url]http://www.youtube.com/watch?v=JEGgUTVsl7k[/url])


roflllllllllllllllllllllmao :D:D:D:DDDDDDDDDDDD
Title: Re: Nerd's Corner
Post by: shesycompany on December 07, 2016, 06:35:50 PM
good enuff video 360? i cant remember but def better than 240 shit on youtube is at 10k just 2x 56k,dam good enuff music is at 1.6 k lool raging  this wasnt around in 2002.works for 2g also.
Title: Re: Nerd's Corner
Post by: Lambchops on December 20, 2016, 01:56:50 AM
Going to cut&paste some of the stuff I have posted in random threads to here, cos I have trouble finding it all....
Title: Re: Nerd's Corner
Post by: Lambchops on December 20, 2016, 01:59:00 AM
there is one WC2 mod that is head and shoulders above everything else absolutely screaming out to be implimented.

That mod is breaking the 128x128 map size limit. Historically I know this has been looked at before, but I dont see why it couldn't be done.

It also leads to another 2 mods that I would like to see, and they are :
 - Increasing the game display from the rather miserly 14x14 window we currently have
 - Breaking the maximum per game unit cap - cannot create unit - this one could possibly be quite easy.

Internally locations are mostly stored as 2 WORD size variables and often passed or referenced as a single DWORD argument so most of the game code already supports a map size of up to 65536x65536. There are, however parts of the code that impliment WORD sized absolute pixel co-ordinates, which restricts things to 2048x2048, but even this would be pretty cool.

Implimentation would not be trivial, but it could be almost all done just by modifying the existing code without actually having to add any new code in.

We would have to do this (at least!)

- Mod existing PUD editors to allow the creation of large maps.

- redefine the valid .PUD check so the clients will accept larger maps

- Mod things like any internal co-ordinate checks that may declare co-ords >127 to be invalid, it would be nice if these would all be based on the map size in the PUD file, but as there are currnetly only 4 legal map sizes there will probably be sections that are hard coded to make calculations based on one of these 4 sizes. All this code would ned to be chased down and modded or re-written.

- Increase any buffer allocations to allow for bigger maps, possibly parts of the executable's .data and .data? sections will also have to be redefined to allow more space.

- Check and mod the display code to allow for larger maps. Scaling for the mini-map is an obvious one, as is the buffer that keeps the background updated (this one is why you can see where trees are chopped even if you don't currently have vision there).

The main view code probably wouldn't have to be changed at all apart from any checks that just flat-out reject large co-ords.

.... Possibly by this time we might know enough about the display code to increase the 14x14 window size by having the internal routines draw the units to a larger buffer, then resizing that image and pasting it onto the existing screen buffer. There are also a bag of issues related to translating mouse input from this resized window.

--> This also leads to running the game at higher screen resolutions, which would be nice, but that would be another BIG mod. Where do you draw the line? It would be nice for it to actually be done before we are all too senile to enjoy it ;)

Breaking the unit cap should just be a matter of increasing the buffer allocation and finding any bits of code that impliment:

if n_units>MAX_UNITS {say "BLEH!"}
Title: Re: Nerd's Corner
Post by: Lambchops on December 20, 2016, 02:00:25 AM
The most I've gotten to is war2 sitting at black screen when I used my maps bigger then 128x128. I think I nulled out the minimap and it no longer crashed. But I was stuck there and clueless. What do you think about that?


I think you gave up to soon ;)

Nah I just ran out of time because of career changes. Plus tons of other projects kept me bottlenecked. All honestly I was tired of being the one trying.


Fair call mate. This I understand.

Having slept on it, I must also say thanks for bit of actual real info. Getting any actual info about how the client works that comes from somebody else's time and effort is always good. Nobody understands better than me that your 'blank screen' story was no doubt the result of many, many hours of hard work.

So here's some thoughts about where to go next:

There are really only 2 questions for this type of thing:

1) what is it doing?
2) how do I make it do what I want?

They inevitably lead back into each other. Working out a bit of 'What is it doing?'(1) leads you to do/mod something (2) which almost never has the effect you thought it would so you go back to (1) and work out what the actual effect was, then try something else(2) etc...

(1) can be a bitch. (2) is the fun part - coming up with elaborate schemes muhahahahahah... ;)

! No longer available (http://www.youtube.com/watch?v=pwlCzYzjYls#)


So, as tends to be the case, you are stuck at (1), however a blank screen should not be a deterrant. The game screen is the least likely place to get any real info about what the internals are doing when you are messing around with them. It generally returns only a boolean 1-working, 0-fucked up.

So what is it doing? If it is not raising any exceptions with the OS then at a guess I would think that either (a) it's stuck in a loop somewhere, or (b) 1 or more buffers have overflowed and corrupted .data or .data? section values related to the video and sound.... or possibly (a) as a result of (b)

You need to have a look at the running process. Belt this stuff around a bit ;)

    MASM32 (http://www.masm32.com/)
    ReadProcessMemory (https://msdn.microsoft.com/en-us/library/windows/desktop/ms680553%28v=vs.85%29.aspx)
    OllyDbg (http://www.ollydbg.de/)
    IDA Pro (https://www.hex-rays.com/products/ida/support/download_freeware.shtml)

Your're welcome. :)
Title: Re: Nerd's Corner
Post by: Lambchops on December 20, 2016, 02:01:36 AM
PE files (https://en.wikipedia.org/wiki/Portable_Executable) contain sections.


Common sections are:

.text (AKA .code) which contains the compiled ML (https://en.wikipedia.org/wiki/Machine_code)

.data   which contains variables and strings etc., that the program can use and modify as it runs

.data? is the same as .data, except that it initially contains no values (uninitialised data). The .data? section is a virtual section that has 0 size in an .exe file but is created when the image is mapped to a process' memory by the system loader. It's a way of pre-defining memory to be allocated, with the bonuse of that memory being inside the module's image.

.rsrc "resource" usually contains things like bitmaps, constant strings (that are not modified during execution), dialog templates etc...



Not all files have all sections, and indeed the names, despite being almost always as listed above, are just a convention. The actual function of a given section is defined by flags set in the Characteristics member of the IMAGE_SECTION_HEADER structure.

Everything you never wanted to know about windows .exe files is here (http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx). (You want the file called "pecoff.docx")

'COFF' stands for Common Object File Format. Executable files started out as a sub-set of COFF files, they share many internal structures. Things like .obj "object" files are COFF files - .obj files are produced by compilers which are then fed to linkers which create the finished .exe file. 


.... anyway so what I mean by this:
....buffers have overflowed and corrupted .data or .data? section values...

      is that when the image is mapped to memory certain areas will have been allowed for certain data, that has an expected maximum size, so there could, for instance be something like this:

Code: [Select]
.data?
mapArray   db 4000h dup (?) ;-- some map array or other
hGLthing   dd ?             ;-- handle to some important GL structure
otherStuff dd ?,?,?,?       ;-- all sorts of other important data

as the max map size is 128x128 = 16384 (0x4000) and the map size is checked when it is loaded, whatever routine that puts data from the map or whatever into that array doesn't bother doing any checking, so when we gymp the 128x128 map size checks, the program just goes right ahead and writes data that is supposed to all fit in that array straight over the top of all the variables that are stored after it.

This is where image data sections can be tricky, because all the references to them are hard coded into the ML instructions. From one angle this makes them very easy to debug because you can always immediately see what is being accessed by a given instruction.

When memory is dynamically allocated, its trickier to debug, but much easier to resize. the same thing could be achieved with:

Code: [Select]
.data?
ptrMapArray   dd ?           ;-- *POINTER* to some map array or other
hGLthing      dd ?           ;-- handle to some important GL structure
otherStuff    dd ?,?,?,?     ;-- all sorts of other important data

then somewhere in the initialization code there is:
Code: [Select]
.code
push 4000h
call GlobalAlloc
mov ptrMapArray,eax     ;  <-- functions return values in the eax register
so this just asks the OS to allocate space for the array then just stores a pointer to the allocated memory in the data section. Later when the program wants to access this array you might see something like:
Code: [Select]
mov edi,ptrMapArray
; ...... then further on
mov [edi+ebx],dl ; ... or whatever
in this case edi woud contain the pointer to the base address of the array, ebx would contain an offset into the array, and the low byte of edx would contain the value it is writing there.

At least that is what the source could look like. Once it is compiled then decompiled, you dont have the benefit of the meaningful variable names that the guy coding it in the first place used, so your:
Code: [Select]
mov edi,ptrMapArray  has become maybe:
Code: [Select]
mov edi,[4A789Ch]... where 0x4A789C is the actual address of that dword in the .data? section (this is what the linker does)

things like:
Code: [Select]
call GlobalAllocwill still be there because GlobalAlloc is exported by name from kernel32.dll and the disassembler will extract the proc name from the IMAGE_EXPORT_DIRECTORY structure in kernel32.

... so if our array is dynamically allocated, and we want to change the max map size from 128x128 to 256x256 all we need to do to resize this particular buffer is change:

Code: [Select]
push 4000h    ; (128x128)
call GlobalAlloc
to:
Code: [Select]
push 10000h    ; (256x256)
call GlobalAlloc

BUT....
....  if this buffer (and not a pointer to it) was itself allocated in the .data? section, to resize it we have to create more space in that section of the PE image.

This in itself is trivial - you just adjust the VirtualSize member of the IMAGE_SECTION_HEADER structure for the .data? section and the system loader will create a larger image - however this doesn't change the ML in the .text section, and as I mentioned the addresses of the variables, and importantly for this case, those after the array (i.e. 'hGLthing') have been hard-coded into the ML instructions by the linker, so the code is still going to read and write the value of that handle to the same location, and the code writing to the array is still going to corrupt it. In this case all we have done is allocate extra memory at the end of the .data? section that isn't used anyway.

To resize this kind of array you would have to increase the size of the .data? section by N bytes, then find every reference to anything in the .data? section that is above the base address of that array (there could be hundreds of addressed data locations with multiple reference to each) and increase all of these addresses, which are hard-coded into the instructions, by N bytes, and to make matters worse there could be pointer tables to some of these locations stored literally anywhere that would all need to be found and adjusted.

With the original source code, you just change your:
Code: [Select]
mapArray   db 4000h dup (?)     to:
Code: [Select]
mapArray   db 10000h dup (?)     then recompile and its done (approx. 5 seconds total)

WHen reverse engineering a complex program this is can be almost impossible, and WC2 was pushing the limits of CPU and RAM capacities back in 1996, so to get the maximum possible performance they used lots of little tricks involving pointer tables to reference things and also to control program flow. It really is a cool chunk of code (Lamby gets all dreamy-eyed and cracks a nerd-boner) but it can be hard to get your head around.

....anyway if faced with this situation I would opt for injecting a small amount of code somewhere that dynamically allocated a larger buffer, and just leave the buffer in the .data? section as a blank space. Then every instruction that accessed the original buffer would have to be located and modded to point to the dynamically allocated one, which could be a bit painful, but nowhere near as painful as doing this for every one of the possibly hundreds of memory locations in the data section that are above the address of the original buffer.... and a nice trick for this type of thing is using a debugger to put a memory-watch on the original buffer then pause execution and report the value of the EIP register whenever it is accessed ;)

And for specifically Blizz related allocation, much of the WC2 stuff is, as you probably know, stored using Mike O'Brians Mo'PaQ format (.mpq files on disk). These are loaded into dynamically allocate memory by various functions exported by ordinal from storm.dll, so if any of these need to be resized it would be done by adjusting the size of the relevent resource in the .mpq archive.


Some notes on the code bits here:
It's all ASM code because that's how I think when I'm doing this stuff, and it really is the only way to think when you're reverse-engineering anything.

DATA DECLARATIONS

Code: [Select]
.data?
hGLthing   dd ?
this just allocates 4 bytes in the .data? section and names that location "hGLthing "
'dd' is 'declare double' it allocates a DWORD
'dw' allocates a WORD (2 bytes)
'db' allocates a BYTE
(also 'dq' allocates a QWORD, but you won't find any of those in WC2)

with this:
Code: [Select]
mapArray   db 4000h dup (?)'dup' means duplicate. Its declaring bytes (db) and its declaring 0x4000 of them.
In all of these the '?' is the data value the location is initialised with.
Because these are in the .data? section which holds only uninitialised data they can't have any defined initial value do they must all be '?'.

In the .data section you can have initialised data so you might see:
Code: [Select]
.data
dwThisVar   dd 0FE339D2h
myByte   db 20h
thisString db "Hello World",0   ;  <-- an initialised zero terminated string
myWords dw 3,3,3,3     ; <-- 4 words all set to 3 (8 bytes all up)
ymWords dw 4 dup (3)   ; <-- exactly the same ( 4 words all set to 3 )

when compiled this .data would look like:
Code: [Select]
D2:39:E3:0F:
20:
48:65:6C:6C:6F:20:57:6F:72:6C:64:00
03:00:03:00:03:00:03:00:
03:00:03:00:03:00:03:00:
(off the to of my head - dont crucify me if I messed up, but you get the idea..)

WC2, was of course written in C, but it all compiles to ML anyway. Apart from ASM (which is for the most part 1:1 ML instructions) C is the lowest level language around and therefore closest related to ASM and the compiled .exe, also most C compilers support in-line ASM code, so performance critical sections of code can be written in ASM, within the C source and then all compiled at once.

Data containers declared in C end up roughly the same as they would have if declare in ASM, i.e. a C pointer variable '*ptrArray' or whatever, if declared globally would end up as a 'ptrArray dd ?' in the data section, whereas if it was declared locally in a procedure it would be created as a stack variable. Which is temporary use of the 'stack' to store values. The stack is a special area of memory that is heavily used by the CPU to shunt numbers around... the 'push' and 'pop' instructions move values onto and off the stack. It acts like a big pile of numbers (FILO) but the current stack location is held in the ESP register ... the stack pointer.

.. and OMG don't look now, but here here comes a bit of compilers, procs and stack frames
  :o

This leads to the actual compiler that was used to compile the source, as they have diferent methods for implimentng procedure calls and allocating local storage. You can allocate 4 bytes of stack space simply with:
Code: [Select]
sub esp,4but it is vital to ensure that the stack is 'balanced' - returned to its correct state before executing the next 'ret' - return instruction. In this case you could
Code: [Select]
add esp,4or just
Code: [Select]
pop eaxwhich would get the value off the stack and put it in the eax register. (push and pop automatically adjust the esp register). The other way to do this is to save the value of esp when you enter a procedure.

The Microsoft compiler does this by repurposing ebp - the base pointer to save the value in esp when entering a procedure, so it might produce something like:
Code: [Select]
push ebp   ; save the value in esp
mov ebp,esp ; use ebp to store the current stack pointer
sub esp,8  ; in this case 8 bytes of local storage has been allocated for the proc (most likely 2 DWORDS)
At this point the arguments that were passed to the procedure are also sitting on the stack behind the return address that was left there by the call instruction that called the proc and the original value of ebp, which we have just stored there. ebp holds the value of the stack pointer after this proc entry, so if it is not changed the passed arguments can be accessed directly using ebp provided we allow for the 8 bytes that these 2 DWORD values use, so the first argument can be accessed at [ebp+8] and assuming its a DWORD (which they almost always are) the second argument is at [ebp+0Ch] etc. At the same time the locals that were allocated with the
Code: [Select]
sub esp,8can be accessed at [ebp-4] and [ebp-8]. This area of the stack, from the start of the passed arguments to the end of any local allocations, for the life of the proc is often referred to as the stack frame for that procedure.

Meanwhile you can merrily push and pop your heart out or call other procs etc. (sending the stack pointer all over the shop) because the position of the stack pointer at the proc entry is stored in ebp, and the entry value of ebp is itself stored on the stack. So when it comes time to exit the proc they just do the following:
Code: [Select]
mov esp,ebp ; <-- restore the stack pointer from the base pointer
pop ebp ; <-- pop the base pointer value off the stack
ret         ; <-- pop the return address off the stack and jmp to that location
In actual fact, Mr Gates made such extensive use of this method that his mates at Intel eventually designed their CPUs with special instructions to acommodate it. The leave instruction does the combination of mov esp,ebp and pop ebp in one hit.

Anybody who has not nodded off by now may have noticed the other issue. Despite having balanced the stack from procedure entry to exit (thus taking care of any locals allocated), whatever arguments were passed to the proc when it was call are still sitting on the stack, as these were pushed there by the caller prior to calling the proc, so esp still has to be increased by an amount equal to the total size of the passed args to put things to rights, but this has to happen after the return value is removed from the stack. Alternate versions of the ret instruction (often denoted as retn) that take a numeric value are used for this, so at the end of a proc that is passed 2 DWORD args, you might see:
Code: [Select]
mov esp,ebp ; <-- restore the stack pointer from the base pointer
pop ebp ; <-- pop the base pointer value off the stack
retn  8     ; <-- pop the return address off the stack, add 8 to esp, then jmp to that address
OR...
Code: [Select]
leave <-- do the esp/ebp square dance
retn  8     ; <-- pop the return address off the stack, add 8 to esp, then jmp to that address

...sadly, however. Blizzard didn't use MASM to compile WC2. By the looks of it, it's Borland code,....

<EDIT>
...Actually, on further investigation, it looks like they used M$ VisualC 2.0 (https://en.wikipedia.org/wiki/Visual_C%2B%2B#Strictly_32-bit_versions)  Presumably there's compiler options for proc layouts/calling conventions etc. Interesting, but changes nothing anyway - it is what it is ;)
</EDIT>


....not that there's anything wrong with that as far as executing it goes, but when decompiled, the stack frame addressing isn't anywhere near as clean to read.

For example, where the MASM code references arg1 by [ebp+8], and anywhere in that proc that you see [ebp+8] you know that it is addressing arg1, Borland doesn't bother with using ebp and just adresses arg1 as [esp+4]

..... until the first time a push instruction is used then 4 is added to esp, so now arg1 is at [esp+8] ... push again its at [esp+0Ch]... then pop something and its back to [esp+8] etc.

So the location of the first argument to a proc is esp + (number of pushes - number of pops +1) x 4 from the proc's entry point.

    EDIT: The exception is, of course, values that are pushed onto the stack as
    arguments to another proc that is being called from within the proc being
    examined, these will be balanced at the exit of the proc being called.


Modern deompilers like IDA (btw use that link to the free version 5 - they don't advertise that, and all the other versions cost mega$) take a fair bit of the hard work out of this for you by getting creative about how they present their disassembly, but due to the way WC2 uses embedded proc call addresses for optimisation you will still see red flags all over the place warning about stack imbalances because there's simply no way for the decompiler to decipher where many of the procs are being called from, so no way for them to be able to interpret what the state of the stack is before the call.
Title: Re: Nerd's Corner
Post by: Lambchops on December 20, 2016, 02:04:27 AM
RE: How WC2 decides which hall a peon exiting a gold mine will return to.


OK don't have time to write a really good explaination but, in a nutshell, it's calculating distance from the top left corner of the mine.

hall is 4x4
mine is 3x3

hall size is taken into account
mine size is not

units are located where their top-left corner is (you can play with the map editor to see this)

Probably they have re-used code from the unit attack AI to find the closest enemy (with annoy factor).


(http://ss.war2.ru/ss/9063.gif)


Its the same thing as the old tower bug, where towers firing up and left would hit other towers that wouldnt fire back, because the size of the destination is being taken into account, but not the size of the source.

In this case you can think of the mine as shooting peons at the hall ;)

As mentioned the distance is what I call "square" distance - the maximum X or Y distance from the top left corner of the mine to the closest point on the hall.

so with that map....

(http://ss.war2.ru/ss/9064.gif)


because of the extra 2 squares in the width of the mine, the distance becomes 5 not 3, which is greater than the distance between the halls (which is 4) so in effect they are the same distance, in which case the peon will go for the hall with the lower Y co-ordinate (as they were both on the .PUD, if u built them it would go for the one you built first.

 =D

EDIT:
... this is why you dont see this bug on the other side of the map where the halls are to the left of the mine, because then the distance is only 3, so its less then the Y offset....

 (btw: the calculations on the pic above should have -1 on them, = 5 not 6 , but u get the idea)
Title: Re: Nerd's Corner
Post by: Lambchops on December 20, 2016, 02:14:49 AM
8-bit palette based graphics
--------------------------------------
Its like this:

For a given bitmap of this type you get to pick your favorite 256 colors from about 1.6 million.

The picture is then made up of those 256 colors. This selection of colors is the "palette".
Then each pixel in the bitmap is one byte which corresponds to the number of one of the colors in the palette.

An 8 bit(1 byte) number can have values 0-255, so an 8 bit image can have at most 256 different colors. However,  when using a palette each part of the color (red,green,blue... or RGB) has a value between 0 and 255, so there are 256^3 (=16777216) colors to choose from, but only 256 of them can be displayed at any one time.

so :
255,0,0         is bright red  (red=255,green=0,blue=0)
20,0,20         is a darkish purple
255,255,255 is bright white
44,44,44       is a darkish grey
66,66,66       is a lighter grey
0,0,0             is black
etc....

A simplified example of how this type of graphics if stored in a file:

HEADER: "I'm a bitmap, im 8-bit, I'm 640 pixels wide by 480 pixels high and i use 256 different colors" (could be <256 but not usually)

PALETTE: list of 256 x 3bytes :  -->  R,G,B for color 0 --> R,G,B for color 1 --> R,G,B for color 2.... etc. to 255 (may be stored in a different order i.e. B,G,R etc)

DATA: 1 byte for each pixel so 640 x 480 =  307,200 bytes*,  - i.e.  color 4, color 162 , color 99 .... or wvr
(*see RLE compression below)

Depending on the file type it will be arranged in slightly different ways: i.e. a BMP is laid out roughly as above, although theres a lot more in the header, which isn't very relevent here, a PNG file has each section compressed using good old PKZip (aka winzip, zlib, 'zip'), PCX is similar to BMP but stores the palette after the pixel data.... and so on.... but regardless of the file, in the end it will be loaded into memory as and array of pixel data  represented by 8-bit indicies into a 256 entry 24 bit color table because that is how that generation of graphics hardware made the pixels on our old CRT monitors light up.

Both BMP and PCX can use a simple form of compression called "run length encoding" or RLE.

RLE simply accounts for long sequences of a single value. For instance if you taks a SS at game start, usually most of your screen will be black, because you havn't scouted anywhere.  In this SS there's maybe half of each pixel line is just a great big line of zeros (pointing to the first palette entry which just happens to be 0,0,0). RLE accounts for this type of thing so instead of actually writing 47 zeros in a row it just makes a little note that says "47 zeros" or "16 '12's" or whatever. The actual way this is written will vary depending on the type of file, however obviously it can be noted using far less than 47 or even 16 bytes (typically 2 or 3).

If it weren't for RLE every SS would be _exactly_ the same size.
Title: Re: Nerd's Corner
Post by: Lambchops on December 20, 2016, 02:16:04 AM
<<< HOW TO FIND THAT SS YOU'RE LOOKING FOR >>>

But now we know why they're different sizes you can actually see this by sorting a bunch of SS by size. They end up sorted by the complexity of the image.

Apart from in-game SS, the smallest files are of Human Victory screens because that is the simplest background image, if you look closely at it, you'll see it has not many colors and large blocks of a single color in the clouds and in the castle wall at the lower left. You'll also find that the smallest of these files are from 8 player games, because the stats bars for units, buildings etc. are single blocks of color, so the more players in the game the more stats bars cover the image and the more compressable the image is. The largest of these files will be from 1v1 games.

The Orc defeat screen comes next at the image is a bit more complex, in actual fact you'll probably find 8 player orc defeat screens creeping in around the same size at 6 player human victory screens. It depends on the actual stats of the players and the length of the player names. A little while after this you'll start getting channel screens. Even though there are lots of chunks of black in the text windows, the blue marbled background and bronze edging are actually fairly intricate so these add up to a fair amount of complexity.

Around the end of your channel screens you'll get your 8 player Orc Victory screens with pre-game lounge screens at around 4 player orc victory size and finally, iroicly the most intricate background is on the Human Defeat screen although mostly because of the massively dithered sky / hills. The end of your 1v1 orc victories will be somewhere around the size of a 4 player human defeat.

Your in-game SS will be scattered throughout. A lot of them will be around the size of the lounge screen, however generally SS from earlier in the game where little scouting has been done especially where black unscouted areas are displayed in the main screen will be smaller. In a large collection of late game SS, those on smaller maps would tend to be statistically smaller than those on 128x128 maps, due to a lower complexity mini-map still being displayed using the same number of screen pixels, however this effect is less important that what is on the main display.

In my current folder the very smallest is from the start of a 2v1 chop game right after I halled, most of the screen and mini-map is black and the file is only 152K. I have a 1v1 Human defeat that is 302K (309,079 bytes) which is larger than the theoretical max size for an uncompressed 640x480 PCX with palette+128byte header which is 308,096 bytes, however there are no uncompressed PCX files and the overhead to support the RLE notation for an image that is not effectively RLE compressable will sometimes actually increase the size of the file as in this case..... yet another reason why dithering is crap.

Another thing you might notice, is that black&white SS from when the game is paused are no smaller that color SS. This might seem strange at first, however there is actually almost no difference between the paused screen/SS and the color one. They are both full 256 color screens, the only difference is that when the game is paused the war2 exe swaps the PALETTE for one that has R,G and B values that are all even for each entry, and therefore all shades of grey. When the game continues the full color palette is replaced, however the pixel data for the display remains unchanged.

But anyway, when you want to find that 1v1 victory screen from last month for bragging rights, sort by size, and - if you were orc, you'll find your 1v1 victories are at the large end of your orc victory screens.

(HINT: They're almost always around the 279KB mark, 1v1 Human wins are about 183KB )

GG
=D

(edit) Supplimental info:

When im talking about "orc defeat" screen, im talking about the one with the picture of an orc on it, which comes up when you are human and lose.... cos the orc is smashing your suff...

...also should mention that for in game SS there will also be differences in the file size between different tilesets i.e. forest!=winter, although this depends what's on screen at the time.
Title: Re: Nerd's Corner
Post by: Lambchops on December 20, 2016, 02:21:46 AM
SERVER LAG: WHAT IT IS AND ISN'T

So the server is lagging a bit at the moment. Sounds like a good time to talk about general lag issues.

Here's what I know about the way WC2 and battle.net worked 15 years ago... we're now using a PvPGN server and an AH server also, so things could be different now. If I'm wrong about any of this stuff, please reply and add your info.... but AFAIK it's like this:

First there's 2 types of network traffic you need to know about:
(don't worry it's really not that technical...)


   UDP: (https://en.wikipedia.org/wiki/User_Datagram_Protocol) User Datagram Protocol
                  and
   TCP: (https://en.wikipedia.org/wiki/Transmission_Control_Protocol) Transmission Control Protocol


The difference is this:
- TCP (https://en.wikipedia.org/wiki/Transmission_Control_Protocol) makes a connection between 2 computers, in this case a player's computer and the server. Once a TCP (https://en.wikipedia.org/wiki/Transmission_Control_Protocol) connection has been made, the TCP (https://en.wikipedia.org/wiki/Transmission_Control_Protocol) protocol guarantees that every message either of them sends to the other is successful. It checks, and if there's a problem, the message is sent again, until it goes through, or eventually the connection is abandoned, whereupon both ends will be notified that the connection has failed.

On the other hand..
- UDP (https://en.wikipedia.org/wiki/User_Datagram_Protocol) does not do this at all. If one computer sends a UDP (https://en.wikipedia.org/wiki/User_Datagram_Protocol) packet to another, it has no idea if the other computer receives it or not. Some program running on the other computer can send back a message confirming the packet arrived, if it wants, but that is not part of the UDP (https://en.wikipedia.org/wiki/User_Datagram_Protocol) protocol (whereas it is built into TCP (https://en.wikipedia.org/wiki/Transmission_Control_Protocol)).

There's also another 2 terms I'm going to use a bit which are:


   IPX: (https://en.wikipedia.org/wiki/Internetwork_Packet_Exchange) Internetwork Packet Exchange
               and
   IP: (https://en.wikipedia.org/wiki/Internet_Protocol) Internet Protocol


- IPX (https://en.wikipedia.org/wiki/Internetwork_Packet_Exchange) is just an old network protocol that is no longer used. Although internally different, as far as the descriptions above go, IPX (https://en.wikipedia.org/wiki/Internetwork_Packet_Exchange) can be considered the same as UDP (https://en.wikipedia.org/wiki/User_Datagram_Protocol). It was popular in the late 80's and early 90's but by '96 it was on the way out and was not widely supported after that.

- IP (https://en.wikipedia.org/wiki/Internet_Protocol) is the basis of the internet. It's that base layer that is sending packets from one "IP Address" to another. You have probably heard the term "TCP/IP" before, well this is the "IP" part. By this terminology the UDP (https://en.wikipedia.org/wiki/User_Datagram_Protocol) traffic could be called "UDP/IP" because the "IP" protocol is operating beneath both of them. Often these days people say "IP" when referring to an IP Address (https://en.wikipedia.org/wiki/IP_address), however here I'm talking about the protocol itself. When I'm talking about an IP address (https://en.wikipedia.org/wiki/IP_address) I say "address".


So... going back to 1996 and Warcraft II:Tides of Darkness (https://en.wikipedia.org/wiki/Warcraft_II:_Tides_of_Darkness) when the internet was still in it's infancy, the guys at Blizzard used a network protocol they were familiar with to implement the pre-battle.net multiplayer games. That was IPX (https://en.wikipedia.org/wiki/Internetwork_Packet_Exchange). For those of you old enough to remember Kali (https://en.wikipedia.org/wiki/Kali_(software)) this is where that fits in. Kali is an IPX (https://en.wikipedia.org/wiki/Internetwork_Packet_Exchange) emulator, so it allowed people to play multiplayer games based on the old IPX (https://en.wikipedia.org/wiki/Internetwork_Packet_Exchange) protocol on that new wonder of the modern age "The Internet!".

But the point is this: the networking side of the game engine has remained pretty much unchanged from 1996. When Blizzard released Warcraft II:Battle.net Edition (https://en.wikipedia.org/wiki/Warcraft II:Battle.net Edition) in 1999, they included all sorts of cool new stuff related to battle.net: server channels, messaging, friend lists etc.., and of course the most important thing - the ability to make a game or join a game. All these battle.net features worked over a TCP (https://en.wikipedia.org/wiki/Transmission_Control_Protocol) connection. This connection is established when you logon to battle.net and (being TCP (https://en.wikipedia.org/wiki/Transmission_Control_Protocol)) it maintains itself, and guarantees the integrity of all messages passed through it.... for example unless the connection fails and one of you is actually dis-connected from the server, a /m to another player NEVER fails, even with bad lag it will still go through eventually.

If you make a game, your client (wc2 program) will talk to the server over this TCP (https://en.wikipedia.org/wiki/Transmission_Control_Protocol) connection and tell it the name of your game and other details. If click the JOIN button the server will talk to your client over this TCP (https://en.wikipedia.org/wiki/Transmission_Control_Protocol) connection and give it a list of games. This list includes the game name, the pud, the settings, and most importantly the IP address (https://en.wikipedia.org/wiki/IP_address) of the host.

It is at THIS point in the process that battle.net ceases to be part of the equation. When you join a game, the internals, for the most part are still exactly the same as they were in 1996, the only difference is that instead of using the old IPX protocol, which was not supported by the internet, BNE substituted the UDP protocol, which was supported. This, however is just wrapping your sandwich in cling-wrap instead of tin-foil, its still a BLT inside. When you join a game (or try to!) you start sending peer-to-peer UPD packets the host's client, which then sends you a list of addresses for the other clients already in the game, and sends your address to them. To successfully join your client needs to make UPD "connections" to all of the other clients in the game.

I say "connections" in quotes, because of course UDP (https://en.wikipedia.org/wiki/User_Datagram_Protocol) (or IPX) does not make connections it just blindly sends packets and hopes they arrive. Your client (the wc2 program) IS, of course keeping track of what packets arrive, and if one connection is losing packets you will see it on the lag screen, or as we know if YOU are the person with the bad connection you will often see several or all of the other players listed on the lag screen, because from your client's point of view packets are missing from lots of other clients.

So this is how WC2 games work over a network, with all of the clients all firing UDP (https://en.wikipedia.org/wiki/User_Datagram_Protocol) packets at each other. So what about the server? Well you trusty TCP connection to the server remains in place, but this connection does not have anything to do with the game. It can't cause game lag. The only thing that can cause game lag is problems with the UDP traffic between the clients.

The BNE client knows to send any chat that starts with a "/" to the server over this TCP connection and the server will then process that message or reply with a WTF? and your client will say "Unknown Command". If the server is lagging it can take 5 or even 10 seconds to get a response. Can you imagine if it took 5 or 10 seconds for every update in the game? There's just no way.... that would be beyond bad lag. Generally speaking for a game not to have annoying lag, the clients needs to update each other every 1 second or so, ideally much less. That means every client needs to be able to send and receive a UPD packet to/from every other client no later than once a second.

BUT, the clients do not, as part of the game send any UPD packets to or receive any UDP (https://en.wikipedia.org/wiki/User_Datagram_Protocol) packets from the server. The only time this happens is when you first login to the server, it does a check to see if you can send/receive UDP packets over port 6112. The reason this will usually succeed even though you may still be unable to host is to do with the way your networking infrastructure (modem/router/network card/drivers etc.) handles traffic. In short, once the TCP (https://en.wikipedia.org/wiki/Transmission_Control_Protocol) connection is established with the server, the underlying IP (https://en.wikipedia.org/wiki/Internet_protocol_suite) "Internet Protocol" automatically sends any traffic from the server to the client at the other end of the connection, regardless of if it is TCP, UDP or whatever.

This is how the "lat trick" works if you haven’t got your game port properly routed. You have a TCP (https://en.wikipedia.org/wiki/Transmission_Control_Protocol) connection to the server, which gives you the IP (https://en.wikipedia.org/wiki/Internet_Protocol) address of the host. So your client sends a UDP (https://en.wikipedia.org/wiki/User_Datagram_Protocol) packet to the host saying "I want to join", but at this point you there hasn't been any communication whatsoever between the two clients. Any channel chat or /m messaging is relayed through the server, so if the game host hasn't got the game port "opened" (properly routed to the client) then when a random UDP (https://en.wikipedia.org/wiki/User_Datagram_Protocol) packet turns up from some random client, the IP (https://en.wikipedia.org/wiki/Internet_Protocol) has no idea what to do with it. But if you alternately make games, then try to join each others' games, you can train the IP (https://en.wikipedia.org/wiki/Internet_Protocol) running in your hardware to associate traffic over that port with a certain IP (https://en.wikipedia.org/wiki/Internet_Protocol) address.

But if you can't get UDP (https://en.wikipedia.org/wiki/User_Datagram_Protocol) packets through to the server when you log in it will give you a warning message saying you won't be able to join games. It will, however still let you log in and chat/message/see the game list etc... everything that happens over the TCP (https://en.wikipedia.org/wiki/Transmission_Control_Protocol) connection. If you join like this you will have the grey "bot" icon which has an unplugged power cord on it.

So back to joining a game. Why can you join a game even if you haven’t got your game port properly routed? Why is it just when you host? This is all IP (https://en.wikipedia.org/wiki/Internet_Protocol) layer stuff, like the "lat trick" above. The problem is with that very first "I want to join" message that your client sends to the game host. If the host's game port isn't routed to the correct end-point then this message turns up from an unknown address on an un-defined port, and the IP (https://en.wikipedia.org/wiki/Internet_Protocol) routing (quite rightly - or you would be vulnerable to all sorts of attack) discards the packet. However, if the host has already said "send me all the packets on port 6112 (or whatever port) then the packet is forwarded to the host's computer, where the wc2 program already has a socket open listening for UDP (https://en.wikipedia.org/wiki/User_Datagram_Protocol) traffic on port 6112.

Once that first message has gone through, the host gives the client a list of addresses for the other clients in the game, and also gives all those other clients the address of the new client joining, and everyone starts sending UDP (https://en.wikipedia.org/wiki/User_Datagram_Protocol) packets at everyone else.... and once you have sent an outbound packet over given port to a given address, the IP (https://en.wikipedia.org/wiki/Internet_Protocol) accepts that your client machine is exchanging data over that port with that external address, so it thereafter routes all incoming traffic to that client.

But, friends and fiends, no amount of server "lag" will make your game lag.... nope, sorry... and here's the proof: what happens when the server crashes during a game? You get a message saying "connection to battle.net lost". This is the TCP (https://en.wikipedia.org/wiki/Transmission_Control_Protocol) connection timing out. As we know TCP (https://en.wikipedia.org/wiki/Transmission_Control_Protocol) connections are "guaranteed" by the TCP (https://en.wikipedia.org/wiki/Transmission_Control_Protocol) protocol. It is internally sending back and forth packets to keep the connection alive and verify that any communication has reached its destination, until your client fails to receive any response from the server for a pre-defined amount of time, when your TCP (https://en.wikipedia.org/wiki/Transmission_Control_Protocol) drivers give up and notify the client that the connection has been broken.

But when this happens does the game end? No, because the server isn't part of the game, once a game has started you could blow up the server with an RPG (https://en.wikipedia.org/wiki/Rocket-propelled_grenade) and it wouldn't stop the game. It stops any messaging etc., any command starting with a "/" but the game continues. When the game ends, even if the server is back up and running you don't go back to the channel, you are back in the pre-connection part of WC2, because the wc2 client wasn't written to automatically attempt to re-establish a TCP (https://en.wikipedia.org/wiki/Transmission_Control_Protocol) connection with the server (this is inherently unsafe as it would have to be storing and re-transmitting your password without your knowledge).

So if there is server lag, it can be slowing down/lagging all the stuff that involves the server: logging in, chatting, messaging, your friend list, getting the game list etc., but it doesn't lag games. Perhaps in theory if there is server lag the TCP (https://en.wikipedia.org/wiki/Transmission_Control_Protocol) service is generating a little bit more network traffic saying "hello? can you hear me?" a bit more often, but if your network is operating on such a tiny amount of bandwidth that it would even notice this then I would expect that you would already be having all sorts of problems.

So what causes lag? Lag,(or lack of it) is a function of the peer-to-peer UDP (https://en.wikipedia.org/wiki/User_Datagram_Protocol) times... or more to the point the worst peer-to-peer route between any two players in the game. There are 2 factors in "worst". Obviously speed is one, but even worse is actual packet loss, where a packet is sent from one place and and just never turns up at its destination. A crackly phone line can do this - or a recalcitrant server (not the game server - just some random internet server). This sort of thing is what causes "conflicts" between two players, that otherwise tend not to have problems. This is because *somewhere* in-between those two end-points is a server that is not doing the right thing with UDP (https://en.wikipedia.org/wiki/User_Datagram_Protocol) traffic... or perhaps with all traffic to/from certain locations ... or maybe it's just plain overloaded.

So while we're on the subject, what's with "/ping"?
The "/ping" or "/p" command is not a battle.net command, it's one of the extra features built into PvPGN (that's the software that runs the war2.ru server - it's a battle.net emulator). "Ping" is a basic networking feature which just sends a packet from one computer to another which asks the remote computer to send it back. The "ping" time is the time it takes for the message to go to the remote location, get processed, and return to where it came from. Usually this is repeated a number of times and an average time is reported.

As we know, when you first login to the server, your /ping will be reported as "0". It appears that checking client ping times is either averaged out over number of checks over a reasonably long period of time, or (more likely) it is a task that the server deems to be low priority and schedules it to be done some time when it is twiddling it's thumbs with nothing better to do. So you wait a few minutes and the server reports a time in milliseconds. Try this for fun: on windows go start-->run then type in "cmd"[ENTER]. This will bring up a DOS style command prompt. Then type "ping google.com"[ENTER]. You can do the same thing from a UNIX machine.

The ping reported by the "/ping" command is the round-trip time from server.war2.ru to your client and back again. It does not necessarily have anything at all to do with game lag, although an excessively high number here can be indicative of a network issue. But as we know, lag is related to peer-to-peer UDP (https://en.wikipedia.org/wiki/User_Datagram_Protocol) times, connection time to the server has nothing to do with it... although if you have a really slow connection you will also have a high server ping time, but a high server ping time does not necessarily mean you have a slow connection.

Another interesting thing here is that right now, when the server is having some genuine lag issues it is reporting my /ping as 247. This is extremely low for me (being in AUS). Normally my /ping is reported at 500+. It's just conjecture, but it could be the result of the server's host provider throttling TCP (https://en.wikipedia.org/wiki/Transmission_Control_Protocol) traffic. As pinging is a "control message", operating on the ICMP (https://en.wikipedia.org/wiki/Internet_Control_Message_Protocol) protocol - which is usually prioritised by servers, if the connection is being throttled at the TCP (https://en.wikipedia.org/wiki/Transmission_Control_Protocol) layer, it could leave other IP (https://en.wikipedia.org/wiki/Internet_Protocol) layer traffic with extra bandwidth, hence faster ping times... or maybe they just switched to a host in AUS?...nah lol.

(((EDIT: more likely by the time I wrote this much, iL had already fixed the server issues so it was all nice and speedy, but at the time I assumed it was still having issues, as I was writing not playing)))

So what's with the green/yellow/red bars on the game list and next to each player when you join a game? These are ping times, but are very different ping times. The bars in the game list is the ping time between the host and the server. When you join a game and are waiting - before it starts, as we know, at this stage it's all about peer-to-peer UDP (https://en.wikipedia.org/wiki/User_Datagram_Protocol) traffic, so those bars are the ping time between you and that other player. If you see one player go red and the rest stay green, its probably their problem. If you see all players suddenly go red, kick your GF off facebook ;) 


....and for the extra bonus points... WHO WAS PAYING ATTENTION? - What small change could have been made to the battle.net protocol to eliminate the whole "opening ports" to host a game issue? ? ? I'll post the answer to that later when everyone has just said "FFS, doesn't that nerd ever shut up?" and completely ignored this post.

Title: Re: Nerd's Corner
Post by: Lambchops on December 20, 2016, 02:26:16 AM
FIXING THE PORT FORWARDING / CAN'T HOST ISSUE

would it be possible to use the lat trick for multiple players? i've only ever tried in 1v1 .. But theoretically if ...........

...... you're talking about our ping in relation to the server.war2.ru.. what about /ping (specific player)   .. the number shot back at me is the time it takes in milliseconds for our computers to communicate with eachother, correct?  so, a player with a ping of 3500 vs 350 is going to make a noticable difference in game.....   

so for the bonus question .. .....the only things i can come up with is somehow form a TCP connection (even if only temporarily) with all of the players on the server so you auto-send/recieve UDP traffic to those players after that   .. or somehow, when you first log onto the server and successfully send/receive UDP packets to the server, have the server forward your UDP packets to all other players on the server so there is a "connection"........


Cool.  8)  Can't quite award full points for the bonus question, but I'm loving the way you're thinking. Definately asking the right questions. I'll write a post with my best answers to this next, But first, here's the answer I wrote yesterday.

... and everyone please note: This is all just theoretical. It seems to make sense to me, but I'm very happy for anyone to explain it to me correctly if any of this is wrong, that's why I started this topic.

....and for the extra bonus points... WHO WAS PAYING ATTENTION? - What small change could have been made to the battle.net protocol to eliminate the whole "opening ports" to host a game issue?

OK then, what do we know about this whole port forwarding lark? Sure, by rights you should have port 6112 (or another if you have configured a change) forwarded to your gaming computer's local address, so that the router knows where to send this traffic. Fine.

But we also know its pretty easy to get around, because even without this you can still join a game and have your client happily sending and receiving UDP packets to and from up to 7 other computers simultaneously. You can even host by using the “lat trick” to get around this.

Although I haven’t actually spelled it out, the reason you can join games is actually exactly the same mechanism as the “lat trick”. By virtue of everyone’s IP address and port being circulated to everyone else by the host, then everyone sending everyone else a UDP packet (and no doubt a few re-tries) over their game port, in effect the “lat trick” is just being done for you automatically for all players in the game.

So why can't you host then?
The problem is with that very first "I want to join" message that your client sends to the game host.

This goes back to the evolution of the game: the multiplayer game was designed to operate on a local network. The battle.net part, despite the nicely integrated graphics etc., is very much a completely different thing onto which they “bolted on” the existing multiplayer game like an after-market carburettor. The game list is little more than a very simple ad for the host's IP address and port, there isn't really any help beyond that. It's up to your client to try to connect to the host, but until it does the host doesn't know that the client is trying to connect.

This is the big difference between hosting and joining, when you join you have already received the host's address from the server and sent outbound traffic when you asked the host if you could join. As mentioned, the host circulates everyone’s addresses so they can all send a few outbound packets to each other to initiate the transaction, and its all good.

So in this entire scheme there is only one point at which a UDP transaction is being attempted where one of the clients is 'blind', .i.e. it hasn't been pre-supplied with the other client's address and port. That is when someone first tries to join a game. The joining client obviously knows the host's address, but the host has no clue. Why? Maybe it was by design to reduce server load on the original battle.net servers, idk, but both clients already have an established TCP connection to the server. So why not?

All that needs to happen is: when a client attempts to join a game, it notifies the server (of course over the TCP), and the server in turn notifies the host of the joining client's address and port, which is 6 lousy bytes! (plus standard transport overhead). Then the host just has to send a few UDP packets out to the joining client. That's all.

The packets can be anything. Null packets would probably work fine, whatever, as long as it doesn't crash the client with garbage, its all good. We have then done our “lat trick” between the host and the joining client which is the only one not already being done. End of hosting issues forever. GG.

 
Want proof that your clients are actually doing the “lat trick” for you when you join a game? Try this:
(I've never tried it, but it should work;)  /me quietly prays that it works...

When a game is over, but before you leave that game, pick somebody there who can't host, (but has a good connection) to host the next game. Then decide on a nice easy game name, like “zz” or something. Then everyone leave at the same time. Have the next host (who can't host) immediately host the game, and everyone else immediately type in “zz” and join. Don't worry about a password, anybody who wasn't in the previous game won't be able to join anyway.

Everyone should be able to join the next game, because the “lat trick” won't have timed out from the previous game. In fact this should work from the pre-game lobby, without even starting the game (maybe all change race before you leave to be sure). I can't see why 4 players, none of whom can host shouldn't be able to decide on a host and a name then, for instance, all join the EF_gamebot game, then leave and have someone successfully host a game. *Of course all players would have to be in the gamebot lobby at the same time, you can't all join and leave one at a time...








Title: Re: Nerd's Corner
Post by: Lambchops on December 20, 2016, 02:29:35 AM
LAG AND THE /PING SERVER COMMAND

.. you're talking about our ping in relation to the server.war2.ru.. what about /ping (specific player)   .. the number shot back at me is the time it takes in milliseconds for our computers to communicate with eachother, correct?  so, a player with a ping of 3500 vs 350 is going to make a noticable difference in game

My understanding of the PvPGN '/ping' command is this: It periodically pings each connected client and keeps a record of the result. In the channel /p will return the last recorded ping time for yourself, in a game it will list the last recorded time for each player in the game, and /p (player) returns the last recorded time for that player. They are all accessing the same info which is the roundtrip -server--> player--> server- time.

The server can't give you a ping time between two clients. The ping has to come from one of the endpoints you are testing (i.e. your computer). Any line starting with '/' is sent to the server, so for this to happen the server would have to send back a request to your wc2 asking it to ping another player then display the results. PvPGN is a generic battle.net emulator and not in any way specific to wc2, and this type of ping display isn't built into wc2, so without mods to the client this can't happen.

But they way you're thinking is right, its all about the connections between each client. Where you DO see this is the 1G --> 6R bars next to each player in the pre-game lobby. But in reality the raw ping time is not the most important factor; you rarely see anyone with anything more that a 3y ping managing to join a game, and they can be fine with regards to lag. What you do see is people's connections going 6R periodically etc. A stable connection.... consistant speeds and no packet loss is much more important than raw speed. Most connections these days are fast enough for wc2, although YES any game where 2 clients are pinging 3500 will have unplayable lag.

(edit)
oh and of course you can ping another player any time you like, as long as you know their IP address. If you are chatting with a friend they can message you their address i.e. 111.222.33.44 and you can just type "ping 111.222.33.44" at a cmd prompt.

.... you can easily find out your external IP address, just google "my ip"


Title: Re: Nerd's Corner
Post by: Lambchops on December 20, 2016, 02:31:41 AM
CONFLICTS

What is the logic behind "conflicts?"  There's a game up and either Player A or Player B can join the game and it doesn't lag, but if both are in, it does.

Lag,(or lack of it) is a function of the peer-to-peer UDP times... or more to the point the worst peer-to-peer route between any two players in the game

The server is not part of the game. All clients talk directly to all other clients. If you have a 2v2 game:  A and B vs. C and D.  then A and B talk to each other.... but A and C also talk to each other .... and A<-->D and B<-->C and B<-->D and C<--->D ..... (did I leave anyone out?) .... so they ALL talk directly to each other.

OK so then we factor in what I was saying about routing in the lat trick post above:

The underpinning logic of the internet, and therefore the internet protocol is that any router can get a packet intended for any address and send it in the right direction to get there... and the next router (server... whatever) will do the same, until the packet eventually gets where its going.

The routing tables in most home routers are pretty simple, they mainly just say "anything that isnt a local address send HERE" with "local address" being defined as whatever your local network is (often 192.168.X.Y or 10.0.0.X combined with a sub-net mask ) and "HERE" being the gateway address supplied by your ISP, which is whatever the IP address is of their server that they are selling you access to....

When you get to your ISP's server it has its own routing table which may or may not just forward everything to a central node, but at some point there will be a bunch of rules like "everything from 0.x.x.x to 127.x.x.x send to server A" and "everything from 128.x.x.x to 255.x.x.x send to server B" ... this is a simple example, there will most likely be a heap more routing rules than that. And those servers will have their own routing tables which will define, for them, the quickest way to send all packets based on their IP addresses... these can also change dynamically depending on what time of day it is and how much load various other servers are under. And of course these servers will have rules telling them to send packets with YOUR ip address back to your ISP's server, which then forwards them to you.

Everybody forwards everybody's traffic... and everybody sends it via whatever route is defined in their routing tables .... in theory this is the "fastest route from A to B" but there may be a variety of other factors at play, i.e. social/political/monetary... who knows? All you know is that you send the info to your ISP, it picks another server to forward it to, which in turn forwards it to another ... etc., until it reaches the destination.... You can check this out on one of the "Ip tools" type websites that does a "traceroute".... this will show you the list of servers that form the link between you and another given server.

SO... back to our 2x2 game... so say, for example, player A is in AUS, player B is in GBR, player C is in USA and player D is in UKR.... perhaps player A can talk to B,C and D fine, same for player B, in fact everyone can talk to everyone else, EXCEPT... somewhere between player C and player D, one of the servers chooses to route the traffic through some shit-box old crappy server in Iceland because they don't pay as much tax that way (or WTF ever). It may even be in one direction only i.e. D can send traffic to C very fast, but when C sends traffic to D there's a problem... (you remember that "ping" times are round trip times so a problem in either direction will show up) ... maybe the guy programming the routers in Iceland was married to a Ukrainian and she ran off with the guy next door, so he said,"screw you and yours" and downgraded all traffic to UKR to the lowest possible priority.... who knows....

Of course these things aren't as simple as that example... it's more likely to do with rival companies downgrading each others' traffic... or a combination of all sorts of things... but the point remains that what causes lag is the speed and reliability of round trip UDP data between all players, and the actual route that the data goes through from player A->B is different from A->C, in fact it may even be different from B->A and all it takes is one crappy or overloaded server to be the "weakest link in the chain" and cause a crappy connection. When it happens that by virtue of whatever happens to be written in the routing tables of a bunch of servers wherever in the world, that one or more of these weak links ends up in the route that data is sent from one player to another, those two players will "conflict".

It may be only between two specific players, but from what I have seen, certian players seem to have problematic connections and will tend to conflict with a few people. One way to fix this *COULD* be to change the route by using a fast proxy or VPN. A VPN establishes a connection over HTTPS between the client and the VPN provider, from where the data would most likely be routed through a different set of servers to the other players. Many servers give priority to this type of traffic so it could even end up being a faster connection, ..... or bloody aweful lol, its a matter of experimenting to find what works


Title: Re: Nerd's Corner
Post by: Lambchops on December 20, 2016, 02:39:04 AM
RE: FORCE CHANGING THE SCREEN RESOLUTION

...you will only end up with either the screen still being displayed in a 640x480 rectangle in the corner, or totally mashed into the first 640*480=307200 (0x4B000)pixels of the screen, depending on the method they use to access the graphics hardware.

All the internals are designed for 640x480, for instance if you read the dword at 0x4D4A94 you'll find a pointer to a 0x4B000 byte buffer that holds the current game screen.... you can do a DIY ss by reading these bytes and the 256x3 byte palette from 0x4AE844 then making a PCX or BMP file out of them.

maybe you could just use a generic image resize and display it at higher res, but you havn't really gained anything doing that - you still really have only 640x480 pixels.

To really change the res, you would have to enlarge the buffer (and any others), and change lots of other stuff.

as and example, if you wanted to display a pixel at certian co-ords you would use:
buffer_address + X+ (Y*screen_width)

so for say the location {333,122} you might do ptrScrBuff + 333 + (122*640)

..but in 800x600 you would need ptrScrBuff+333+(122*800), except I think you'll find LOTS of places where the 640 is hard coded... idk never tried to find them. so if you change the display mode and enlarge the buffer to 800x600= 0x75300 bytes, then lots of things... probably the GRP decode routine for starters... would still calculate 333+(122*640), so instead of {333,122} you end up at  {13,98}... then the next row of pixels could end up on the other side of the screen etc.

Not a small job, but I'd love to see it done  :)
Title: Re: Nerd's Corner
Post by: Lambchops on December 20, 2016, 02:41:08 AM
Damn! :)

Okay so their is a referenced string for display adapter you can find with cheat engine, etc. Change that also!

Also another tip! Try to hex ddraw.dll!

Actually, now I look at it, bne is just using standard windows gdi stuff. The DOS version would use interrupt 16 and mode 257. But wc2.exe and storm.dll only import graphics stuff from GDI32.dll and USER32.dll, so its all just device contexts...

ddraw.dll (directX) isn't imported by anything, in the traditional way. It's being dynamically loaded by one of the sneaky little embedded code modules blizz use. It seems they only use:

CreateBackSurface
SetPalette
CreatePrimarySurface
SetDisplayMode
DirectDrawCreate

Which is just a very basic set of initialization routines. Also there's a help message in there for the event where it can't use directX, telling you to set your desktop to 640x480x256.

There's a few calls to GetDesktopWindow followed by GetDC, this gets the device context of the windows desktop (being the top level window), so it looks like its, in effect just resizing the desktop to 640x480 then writing directly to it. Possibly. At lot of it relates to dialog boxes and stuff, hard to tell without spending more time. Anyway, anyone who understands standard windows GDI programming should be able to have a go at it...

------edit:
Code: [Select]
HRESULT SetDisplayMode(
                         dwWidth,
                         dwHeight,
                         dwBPP,
                         dwRefreshRate,
                         dwFlags       );
Title: Re: Nerd's Corner
Post by: Lambchops on December 20, 2016, 02:42:17 AM
There's a few calls to GetDesktopWindow followed by GetDC, this gets the device context of the windows desktop (being the top level window), so it looks like its, in effect just resizing the desktop to 640x480 then writing directly to it. Possibly. At lot of it relates to dialog boxes and stuff, hard to tell without spending more time.


Was having a look at other threads and found this desktop SS from USA~Archer. I get a similar issue when I am alt-tabbed and I disconnect from the network, but seeing it side-by-side with the window is helpful.

(http://forum.war2.ru/index.php?action=dlattach;topic=897.0;attach=236)

After seeing this I would guess the reasons would be:

 - WC2 was originally written for DOS. When they made BNE they needed to port the display code for windows, so somebody came up with the bit of DirectX code to change the display to 640x480x256 and provide a handle to it, so the original dos code could use that.

 - The basic channel screen frame etc. uses this handle, but the code that writes the text and dialog boxes etc. to the screen was done seperately, and that is what is being done with the calls I mentioned above.

This is what is happening in this SS. The borders etc. are being written to the DC of the window, but the text is being written directly to the desktop so its appearing in the top-left 640x480 section of the desktop, regardless of the position of the window.

Anyway, the point is I would guess that replacing all (or perhaps most of) the calls to GetDesktopWindow with calls to GetActiveWindow could fix this problem. If not, then converting the co-ords with either ClientToScreen or MapWindowPoints should work, but this would be a little bit trickier to patch as it isn't a straight 1:1 replacement.





Title: Re: Nerd's Corner
Post by: Lambchops on December 20, 2016, 02:45:13 AM
PORT FORWARDING IN DD-WRT / VPNs

OK so I fired up the router (it's a NETGEAR WNDR4500) and discovered I had reflashed the stock firmware before mothballing it, so I put DD-WRT back on it, probably better to start from a clean install anyway. Its build 26138 – about 18 months old.

After the standard setup stuff – gateway address, DHCP, DNS etc. I just plugged in the port (6112) and the local IP of my gaming machine (for the purposes of this exercise I called it 192.168.3.33) and I was able to host without issue. But... I'm not using a VPN so that may be a causing problems.

OK So…. Port forwarding:

(http://ss.war2.ru/ss/9047.gif)

It's in the NAT section. This is not actually network address translation, but from a coding perspective its right there in the part thats deciding where to send packets based on transport layer info (which is a big part of what NAT does), so it makes sense that it would be grouped there on the config page. The important thing is that 'port from' and 'port to' are both the same so nothing is being translated, its just sending everything stamped with a '6112' to LAN address 192.168.3.33. In fact this should safeguard the passage of port 6112 traffic through any NAT that the router is a party to, although it won't help you if somebody upstream is switching ports on you.

Some protocols can safely pass through NAT, or actually they would be totally destroyed by NAT so they are given a pass. Things like IPsec (https://en.wikipedia.org/wiki/IPsec), so if you have an option to use one of these, it might help.
Title: Re: Nerd's Corner
Post by: Lambchops on December 20, 2016, 02:46:23 AM
you, sir, are an actual gentleman. thank you very much bro. not actually putting in a range might do the trick, will get stuck into this when i sober up in the mornin. thanks again

YW, glad I could help  :)

Yeah, there's no reason to forward anything apart from UDP on your game port. In most cases forwarding others probably won't hurt, but its unnecessary and could possibly confuse things a bit, especially if you're trying to run more than one client from the same LAN.

Remember you can already join/chat/message etc. without forwarding anything at all. The only thing that isn't getting through is the initial "hi, can I join your game?" message from other players.

When you host, part of the info in the game list is your game port, so people trying to join send UDP packets over that port to your public IP address. The whole deal with port forwarding to host WC2 games is just telling your router to send you those packets.

             UDP:YourPort   -->   your computer's LAN address

Title: Re: Nerd's Corner
Post by: Lambchops on December 20, 2016, 03:00:18 AM
>8 PLAYER GAME

As has been mentioned, Wargus is a completely different program to WC2. It's a ground up re-write ....  fan-fiction, if you will. Its pretty cool, but there is no more chance of anything from Wargus applying to WC2 than stuff from Mario Kart (https://en.wikipedia.org/wiki/Mario_Kart).

Sure, if you put the time into it you could convert some of the graphics to .grp and import them into the game, (and lets face it, that would be freakin AWESOME :P) but sadly its not going to give you a boost button or make them jump off a ramp into you opponents base.

As for using 16 players - or at least having units assigned to 16 different players i.e. for rescue and gaining multiple races for each player. This seems to stem from .PUD format allowing for up to 16 players in some sections.

I'd hate to spoil the party, but here's a small bit of info for you.

Player 16 = Dead.
That's where the pixels go when they are punched to death by ogre-magi.

Player 15 is also used for internal purposes. Players 9-14 .... maybe but I doubt they're ever going to function properly, all the player controlling stuff is written for players 1-8.

Pretty much everything apart from the map is a unit, spell effects etc. are units with short lives, but the game engine isn't designed to let you select them or move them etc.
Title: Re: Nerd's Corner
Post by: Lambchops on December 20, 2016, 03:02:07 AM
ATTACK SPEED / MOVEMENT SPEED

speed i still havent found it.
but attacks can be changed and range.

Attacks and range are in the the PUD format, speed is not (attack speed or movement speed).

Also certianly there is no guaranteed attack speed for units. Melee units tend to just hit anything in range, but cats and drags etc. do not necessarily do this. Telling a cat to attack something in range doesn't guarantee it will do it asap. Also peons/peasants move slower when they are carrying.

This sort of thing tends to suggest that the timing of such things is built into the AI, there must still be a bunch of numbers somewhere that at the very least describes a minimum time interval for units taking their next action, but it may or may not be a list for each unit type, as with most unit attributes.

The pathing code advance calculates the next 20 steps for all moving units, then adjusts if that path is blocked, but it does this independantly of the unit's speed, the timing is being dictated somewhere in the core of the engine.

It's facinating stuff, I wish I had more time to look at it right now.


Title: Re: Nerd's Corner
Post by: RipE[Eur0] on December 21, 2016, 11:19:55 AM
nice.

i checked out my phone. i cant forward ports, and i didnt find an application for ports.

so. i will never host untill the server admins have worked it out.

Title: Re: Nerd's Corner
Post by: Lambchops on February 20, 2017, 05:17:15 AM
Old PUD File Editor

Yeah, can you share that map editor?

sure np.

Like i say, Its a bit rough around the edges but does some useful stuff.

Will thumbnail all your maps. The clipboard is good. Mirroring is good for making symmatrical maps. cut/paste is handy - its a bit kluncky but it works MOST OF THE TIME - crashes occasionally. Its a really old app and it needs re-writing but I just dont care hard enough...


and it's got this uber kewl splash screen xD..
(http://ss.war2.ru/ss/9095.gif)
     DOWNLOAD (http://forum.war2.ru/index.php?action=dlattach;topic=3778.0;attach=2082)

oh and I added the unbreakable wall thing recently too.
Will also swap player units... like of u want to put teal where oj is or something, just swaps them all.
"Set all mines to max" if you're making a custom saves you selecting every mine and doing it by hand etc...

if you want to copy/paste to a different map: copy then file->load next map then paste (doesn't use system clipboard).

have a play round with it. you'll work it out.

the thumbnail thing just creates a small .bmp file for each .pud then u can just view like this in windows:


(http://ss.war2.ru/ss/9096.gif)
( just select "thumbnails" from the menu then point the dialog at your "maps" folder)



--> oh and let me know if it just crashes instantly, some of my older stuff had issues with DEP (data execution protection) because of the way i used to embed chunks of ML, don't remember the PUD editor having any of that, but if it does i'll have a look and weed it out <<<<
Title: Re: Nerd's Corner
Post by: Lambchops on February 20, 2017, 08:58:20 PM
As i see, a C++ class/library to include into war2 loader.

Just thouhgt: would be great to find good network programmer/engineer for war2 project:
We could handle the whole war2 network behavior ourselves: to guarantee all the UDP connections between all the cilents, to manage and find optimal routes for that connections


Sounds like fun, but as I say, a lot of work. Personally I have far too much to do right now to be able to seriously commit to a project like this, although if you want to do it, I will help where I can. Even just writing these posts is taking more time than I really should be spending on gaming.

There are a lot of things to consider when routing network flow. Here is an example of some of the basic issues: [Network Flow I] (http://www.cs.cmu.edu/~avrim/451f11/lectures/lect1025.pdf) …. after that you can start factoring in some of the more technical bits.

Perhaps there is already an open source solution that would fit what we need for wc2, which could save the need to code the flow analysis/decision making from scratch, but even assuming that is is already done, just hooking this in along with the necessary support code to adapt the client to use it is a big job.

We must also remember that what we are always striving for is reliability and minimum latency, not maximum flow. Every extra step that is placed into the nework logic inheranty adds latency. A small amount of this to side-step disasterous connections between individual clients could add up to a net gain for the reliability of individual games, but too much of it and you're using a flame-thrower to get the weeds out of your lawn… the weeds are gone, but so is the lawn.

reroute if clients will suddenly change their IP during the game.
I think this would be a very rare event.

UDP over internet is far from perfect and has lots problems. So, some kind of layer between raw war2 UDP and internet (like distributed UDP network between war2 clients) based on new technologies and implementation is what we need.


UDP packects are inherantly no less likely to arrive at their destination than any other type. By rights, it *SHOULD* make absolutely no difference. There is a difference, but that is not due to any problem with the UDP spec, it does exactly what it was designed for. An explaination requires a bit of discussion about netowork data streams, so.......  Packets are arranged something like this like this:

This is a very simplified version just to illustrate the principles, there are other fields not listed here

Internet Layer:
Code: [Select]
An IP packet:

{version, size, protocol, src address, dst address, {Payload - 'size' bytes of data}}

Transport Layer:
Code: [Select]


UDP Packet:

       {src port, dst port, size, checksum, {Payload - 'size' bytes of data}}

TCP Packet:

      {src port, dst port, sequence number, size, checksum, {Payload - 'size' bytes of data}}


So at the internet layer, a UDP packet looks something like this:

Code: [Select]

{version, size1, 0x11, src address, dst address, {src port, dst port, size2, checksum, {Payload - 'size2' bytes of data}}}

Here size1 is the size of the entire UDP packet, which is the payload for the IP packet, and size2 is the size of the data which is the payload for the UDP packet.

... and a TCP packet would be something like:
Code: [Select]

{version, size1, 0x06, src address, dst address, {src port, dst port, X , size2, checksum, {Payload - 'size2' bytes of data}}}


So accoring to the original design, the IP packets are only being routed based on the information in the IP header which is pretty much just the address and the number of bytes. Its only when the packet is received by the network drivers at the other end that the IP headers are stripped and the payload is then passed on to the appropriate transport layer driver that the internal headers are inspected.

The IP header does, however contain a protocol (https://en.wikipedia.org/wiki/List_of_IP_protocol_numbers) field, which for these 2 cases will be set to either 0x06 for TCP or 0x11 for UDP, so servers along the way can see what type of data is in the payload and possibly decide to do something different with the packet.

Without an actual decision being made about it somewhere along the way, neither TCP, UDP or any other transport layer protocol is any more likely to be reliable than another. The main difference between TCP and UDP packets is the inclusion of the sequence number in TCP and the behaviour of the drivers handling transaction. TCP simply puts a number on each packet when it is sent, like the page number on a book.

So if the TCP driver receives packets 1,2,3,4,6,7,8 it sends back a request saying "hey I'm missing packet 5 - send that again!", and it blocks forwarding packets 6,7,8… etc. to the application until packet 5 is received and inserted into its correct spot in the data stream. This great for reliable data transfer, but terrible for anything that requires real-time transfer. This is why things like VoIP and live video streaming use UDP, because for them having the latest real-time data is more important than worrying about a tiny fraction of the data that was not received.

BUT…. and this is the big but… what if you are attempting to write firmware for a network router? What do you do when there is congestion in the network and you simply cannot transmit all of the data that you have received? Lets pretend that you are only getting TCP and UDP packets (indeed they make up the majority of the transport layer bandwidth). What if you drop a TCP packet? The driver at the other end is just going to send back a request for the missing packet, then the source is going to re-transmit the packet and you have just doubled your congestion problem.

On the other hand, most of the UDP traffic is stuff like VoIP and you know that a) losing 1 in every N packets in a VoIP stream doesn't stop it from functioning, it just gives a corresponding loss in signal quality and more importantly b) If you drop a UDP packet, most times this will just be accepted by the clients and you won't have to handle the traffic from them requesting and retransmitting the lost packet. Considering this, its no surprise that generally when a server is facing network conjestion issues the first thing they start doing is dropping UDP packets.

O.K. so lets just stamp all our packets with a 0x06 instead of an 0x11 right? So the servers will think the payload is TCP and be less likely to drop it… Nice in theory but there's a couple of issues with this. Firstly, the IP packet header is being written at the driver level, so it's not just a matter of altering wc2 client you would have to be hacking the network services on the machine it's running on (no thanks) and second, stateful and application layer firewalls are quite commonplace these days. These firewalls do inspect the payloads of internet, transport and even application layer packets looking for things like malicious activeX controls and the like. These would instantly flag incorrectly labeled IP packets and a the very least delay them if not block them all together.

ISPs also use a certain degree of this type of packet inspection to manage their bandwidth, for instance on Monday afternoons my torrenting speeds drop to about 10% of what I get the rest of the week. Torrents are distributed via anonymous peer-to-peer connections, and in theory my ISP should have not even know that the packets contain torrent data, but you can be very sure that they do.

These types of issues are why I suggested using a fast VPN  *COULD* be a way to improve a bad connection. Inherantly VPNs have a lot more overheads associated with them so should have higher latency that just sending UDP packets. However govornments, corporations and all sorts of high paying customers for the ISPs tend to use VPNs, and being secure, there is no way for anyone to have a look inside and know exactly whats there, as a result many ISPs tend to give high priority to this type of traffic, and they are the last type of packet that is likely to be vonluntarily dropped by a server.

…. and at this point, like so much that happens in our little community, our issues start to become less about network engineering and more about social engineering. ;)
Title: Re: Nerd's Corner
Post by: shesycompany on February 21, 2017, 01:09:17 AM
hobby ;)
Title: Re: Nerd's Corner
Post by: Lambchops on February 21, 2017, 03:02:50 AM
hobby ;)
Heh... ya I've just been looking up some info from old posts. I collect em here so I don't have to search next time...  but OMG that lambchops goes on a bit doesn't he? Every time I look for some thingy I find another I find another 6 pages of his drivel  ;D
Title: Re: Nerd's Corner
Post by: Lambchops on February 28, 2017, 12:30:20 AM
CHANGING THE MINIMAP PLAYER DISPLAY COLORS
(RE: Black to Pink)

I've never really looked at Messiah's black to pink mod, but from what I understand it is an edit of the graphics resources in the game MPQ data.

As far as just changing the color that appears on the mini-map, not the unit graphics here's the relevant info IIRC:

  The black player is rendered using the grey palette entry 0xE4 (228). You can edit this palette entry and change it to pink (or whatever), however this will also change any other pixels on the screen that are that shade of grey, which might look a bit weird.

 The palette entry that is used for each player is stored in an 8 element byte array at 0x004A48CC, this changes from game to game unless the game is fixed order, as the colors are randomly assigned to each player slot at game start.

The minimap black-to-pink in my anticrap (http://forum.war2.ru/index.php?action=dlattach;topic=2852.0;attach=986) prog works by finding the 0xE4 entry in these 8 bytes at the start of each game and writing 0xFD there instead.
Title: Re: Nerd's Corner
Post by: Lambchops on February 28, 2017, 04:04:31 AM
Just had a look at the unit color display (haven't checked out this stuff for years), so its like this:

There are 4 palette entries for each of the 8 player colors that are used to display the units
i.e. 4 shades of red, 4 shades of blue, 4 shades of purple etc...

for 7 of the 8 colors these are all in a block from palette entries D0 thru EB. For some reason the yellow entries are at 0C -> 0F ... which is kinda weird but makes no difference really.

They look like this:

(http://ss.war2.ru/ss/9158.gif)

For 5 of the 8 players, the first of these 4 colors is also used for the mini-map color, but for blue, yellow and white the mini-map colors are different.

Here's the actual colors for all of it
Code: [Select]
           MM     UNITS
--------------------------
RED        D0      D0-D3
BLUE       01 *    D4-D7
TEAL       D8      D8-DB
PURP       DC      DC-DF
OJ         E0      E0-E3
BLACK      E4      E4-E7
WHITE      FF *    E8-EB
YELLOW     02 *    0C-0F


It looks like the mini-map colors are taken from a source list at 0x004A48AC

So if you hex edit the WC2 exe at 0xA48B1 you can permenantly set the palette entry for black i.e. you should find 0xE4 at this location, if you change that to 0xFD you will always have pink (just worked for me).

...or if you don't like pink so much you can change this to 0xEA and it will be a lighter shade of grey that much is easier to see than the original mini-map "black" color.

However this begs the question how does Messiah's B2P mod change the mm color if this is hard coded into the exe? I'm guessing there's a "[/]Use default data" thingy somewhere, so if you include modified graphics it will override these default colors.

(EDIT)
or more likely it's just changing the palette colors, but the entry indexes remain unchanged...



Title: Re: Nerd's Corner
Post by: Lambchops on February 28, 2017, 04:17:48 AM
Here's what the 0xEA grey looks like on the mini-map

(http://ss.war2.ru/ss/9159.gif)

I like it  8)
Title: Re: Nerd's Corner
Post by: Lambchops on February 28, 2017, 04:36:06 AM
Here's a little app that will patch black to grey if you're not into hex editing.
GG
Title: Re: Nerd's Corner
Post by: Incos on February 28, 2017, 09:57:51 AM
Very nice follow through lamb. I love it. The gray looks good! Just looks black in game for some reason. Would hexing the war2.exe fix that as well or do you have to Olga through each individual unit and change color
Title: Re: Nerd's Corner
Post by: Lambchops on February 28, 2017, 06:22:40 PM
Very nice follow through lamb. I love it. The gray looks good!

Thanks mate  :)

Just looks black in game for some reason

How so? On my screen it looks exactly like the SS above. If you apply the patch does your mini-map not look like that?

I've noticed it sometimes looks like its got a slight purplish tint to it.. or maybe thats just my eyes playing tricks on me.. cos my brain is wired to expect certian colors up there from looking at it for so many years..

...or do you mean the on-screen unit graphics... like ogres or whatever? This is only intended to change the mini-map color... although possibly that could be changed too. IDK, havn't looked at it.
Title: Re: Nerd's Corner
Post by: Incos on February 28, 2017, 06:40:06 PM
That's cool mate, I haven't touched the computer in awhile. Work got me tied up.  I meant the onscreen as well. It's clear you found the code for the mini map which is awesome.  Now I wonder if he individually changed the palette of each bmp or if this is also in the war2.exe.. I will be looking at it tonight.

The only reason I ask is i want to learn. I would like to change the black ogres as well possibly some of the colors to dif variations.

It also opens the door for a bigger player Warcraft 2, such as 10 players or 12 players. Sc2 and wc3 both do it.  I just wonder if it's the engine holding it back as well.

I know some of the guys have looked into it already. And say it's impossible for a bigger map than 128x128
Title: Re: Nerd's Corner
Post by: shesycompany on February 28, 2017, 09:05:26 PM
u would want to make a new engine.
there's been quite a few of these dudes...get a little team together...

im using game maker, probably will piddle around somemore.

someone like lamb can possibly doit with bnets :o
Title: Re: Nerd's Corner
Post by: Incos on February 28, 2017, 09:18:35 PM
Yeah lamb seems really advanced. Probably one of the only people on server that could even implement that
Title: Re: Nerd's Corner
Post by: Incos on February 28, 2017, 09:48:26 PM
Was able to recreate the hexing of the .exe file, i am curious on how you know which binary held the mini map file?
Title: Re: Nerd's Corner
Post by: Lambchops on March 01, 2017, 04:19:58 AM
Was able to recreate the hexing of the .exe file, i am curious on how you know which binary held the mini map file?


Well if you read through the posts above... and maybe on the black to pink thread... you can pretty much see my thought process because I wrote the posts as I was doing it.

However... just to add that plot twist that every good detective story needs: I was cheating - I didn't just work it all out now - I copied some work from a program written by some dude called ItMustBeLove in 2009 (aka Lambchops).... yeah me lol.

But what on earth I actually did 7 years ago I don't really know... i could guess - similar stuff to what I'm doing now.

I would guess that I probably first found the source list that I'm now patching, but at the time I was producing a small demo program to demonstrate that I could actually do stuff, not just get on the forum and talk crap. The plan was for a modified exe later on with all sorts of patches applied, the demo program was just an "instant" thing. So....

Now i've rediscovered it all, I'm pretty sure back then I followed the trail forwards from the source list to where it was implimented on a per game basis, then made a "live patch" that patched the current game colors in the active process memory. Still can't really remember, but that sounds about right.

So 7 years later when I wanted some info on this stuff, I knew I had worked it out before, so the first thing I did was disassemble my old app (lost the source  :-X but that's another story) and worked out what I did back then...

From my old anticrap app i knew I was searching the random array at 0x004A48CC for E4 and changing it to FD.. and I remember that this was hot pink not the nice pastel shade that comes with Messiah's B2P, because I remember Blid politely indicating that it was all but burning his retinas out lol...

Anyway this had me looking in the right places, so I poked around a bit and came up with this list:

Code: [Select]
RED        D0      D0-D3
BLUE       01 *    D4-D7
TEAL       D8      D8-DB
PURP       DC      DC-DF
OJ         E0      E0-E3
BLACK      E4      E4-E7
WHITE      FF *    E8-EB
YELLOW     02 *    0C-0F

Considering the list and the mechanism it seemed logical that if the game was randomising the entries for each player in a game (but not for fixed order games) then there must be a list of these entries somewhere IN ORDER i.e. Player 1 = Red, Player 2 = Blue, etc.  -  i.e. a source list.

.... at that point I just searched the PE image for that sequence of bytes: D0,01,08,DC,E0,E4,FF,02 and found it a stone's throw away from the randomised list.... obviously the I did a quick edit and test, and it worked  :)


Oh, and as for working out what palette indexes were being used so I had something to search for, they just came originally from good old fashioned, common or garden variety Screen-Shots. 8-bit palette based graphics are ideal for this sort of stuff.






Actually, here: you'll love this (well I do anyway). How technical is this stuff OMG! lol  ;)  not as technical as you might think sometimes, logic is always the best tool and there's HUGE bonus points for cheating and making stuff dead simple. Simple is Sexy. :fro:




--> Let's find what palette indicies are used to display the colors on BLUE units.

Ok so first we need to find a SS that displays a blue unit. Here's one:

(http://ss.war2.ru/ss/9161.gif)

Cool. If we zoom in on that little guy in the bottom right we can clearly see the 4 shades of blue that are used for him and his whole tribe.

(http://ss.war2.ru/ss/9162.gif)

So now we need to know what the actual numbers are in this PCX file that reference the palette entry that is used to render this little group of pixels....

... so we can work out the exact (x,y) co-ordinates of each pixel we want to test, then find it's source in the PCX file.

Ok so: 

The specs for PCX format are freely available online,

       * source these and work out the sizes for the various header structures

       * then locate the pixel data.

       * then we discover that (of course) all PCX files are RLE compressed... not a huge deal

       * decomopress the pixel data

       * finally we apply the love-child of our (x,y) co-ords and the (w,h) dimension of the PCX file to the decompressed data stream and....

.... hey presto! if we got our sums right we got the palette index of the RGB values for that pixel.
:)

Still that's a lot of sums, I could have messed something up  :(  ...  I would want to make sure it was the right value by writing back some kind of a test......   say altering this palette entry, or altering the pixmap by copying this entry to.......  um ....and by now we're half way through next week.......



....... hmmm






..... mmmm ......








                            ......  OR  ......


We could have a nice refreshing glass of sanity and say: NAH .... there's got to be an easier way..

Here's what I did:

... for starters I used Irfanview (http://www.irfanview.com/) to convert the PCX SS to a .BMP so I could easily edit it. Probably PaintshopPro or whatever else would work just as well, but the main thing is to MAKE SURE THAT IT STAYS AN 8 BIT PALETTIZED IMAGE (256 COLOR),  if it get's converted to 24-bit you're going nowhere. This takes about 6 or 7 seconds (throw the PCX at irfanview select "Save As" .BMP - done.

At this point we're already way ahead because .BMP files aren't (by default) RLE encoded, - although they can be, however ALL PCX files are, it's part of the spec. So, no need to worry about that, just the header files, let's see there's a BITMAP_INFO_HEADER... and blah blah blah... nuh-uh ... not if I dont have to  :P

 Hard work? No Problem Every time I have to, I'll kick it's ass... but when I don't have to? ..... I'll leave that for the fools and martyrs.... 

(http://ss.war2.ru/ss/9163.gif)

so I just opened the BMP in M$ Paint and used the magnifying glass thingy to zoom in on our little guy.... and then there's a little eye-dropper thingy that lets you select a color from the image.... and of course its a paint app, so we can draw a block of color.... so let's just get the lightest blue shade and make a Big Blue Blob

(http://ss.war2.ru/ss/9164.gif)


... damn, that was easy... let's do it again for the other 3 colors....


(http://ss.war2.ru/ss/9165.gif)


Sheesh, well that took all of 45 seconds. OK, so we get rid of our little magnifying-glass zoom-thingy and our SS looks like this:


(http://ss.war2.ru/ss/9166.gif)


Well I'm really in the mood for some graffitti today so let's do it again!

Now we've got those nice friendly pads of color to sample....

....... eye-dropper..... color rectangle,  .... eye-dropper..... color rectangle,  .... eye-dropper..... color rectangle....., .... eye-dropper..... color rectangle ......   

   ...AND TA-DAH! the finished product... what a materpiece!


(http://ss.war2.ru/ss/9167.gif)



Now we calculate the.... header sizes... pixmap offset... dword alignment... RLE encoding.... BAH!   ;D  Yall just KNOW I'm not gonna... hehe









  --> just toss it into a hex-editor and scroll down a few pages until:


(http://ss.war2.ru/ss/9168.gif)


Now I didn't do even one simple piece of arithmatic, but can there be any doubt whatsoever what the 4 palette entries are? I think no.

      If only everything about reverse engineering software was like this.

---------------------------------------

So I did this for each of the 8 player minimap colors, then as we know the player colors for a fixed order game order (if you can't remember just look at the menu from the Blizzard .PUD editor) I arranged the 8 bytes in that order, then did a search for those 8 bytes. BINGO!





  ...and call me a nerdy nutter, but i absolutely LOVE that such absolutely crude and uncalculated methods can pin-point the precise location to do exactly what I set out to do, in over 700,000 bytes of exe file . That shiz just makes me giggle like a school-girl  ;D





IDK, perhaps I should make out that it was all extremely complicated and it took me leading a team of NASA software engineers programming a network of helium cooled quantum processors to calculate all the variables because I'm such a freakin guru xD NAH... just 'cos I'm learning some GOW doesn't mean I have to be a complete tosser...



Title: Re: Nerd's Corner
Post by: shesycompany on March 01, 2017, 04:26:02 AM
 :-*
Title: Re: Nerd's Corner
Post by: Lambchops on March 01, 2017, 04:52:50 AM
:-*

LOL.. right back at ya, big guy  8)
Title: Re: Nerd's Corner
Post by: Incos on March 01, 2017, 07:34:32 PM
Keeps giving meerrorinwar2 whenever I try to edit palette of specific unit. I tried the black lumber mill to lime green and didn't work... zzzz I need to get experienced. What code is Warcraft 2?maybe I can take a course
Title: Re: Nerd's Corner
Post by: Lambchops on March 01, 2017, 07:45:40 PM
Ok, firstly apologies to your good self, Incos. I started writing a quick reply about the subjects you mentioned, but as it turned out when I started writing I found I had quite a bit to say. This post rapidly turned into a monster, In fact I just started writing about some of my ideas for a new WC2 front end then went to preview it and it got rejected because its over 20,000 characters .... OMW ;D As a result I had to cut that description (which wasn't so far under the limit on its own) and will post it following this bit (which isn't too much shorter than the other bit) So sorry for turning your simple enquiry into a platform for a whole bunch of stuff that I wanted to talk about ....... but there is some info related to the topics you brought up in here somewhere.

Now I wonder if he individually changed the palette of each bmp or if this is also in the war2.exe.. I will be looking at it tonight.

The only reason I ask is i want to learn. I would like to change the black ogres as well possibly some of the colors to dif variations.

It also opens the door for a bigger player Warcraft 2, such as 10 players or 12 players. Sc2 and wc3 both do it.  I just wonder if it's the engine holding it back as well.

I know some of the guys have looked into it already. And say it's impossible for a bigger map than 128x128



Yes ... but not SC1 AFAIK. You may be aware that SC1 was basically WC2.5   It's based on the WC2 game engine, which was expanded in 2 main ways  (a) there's 3 races and (b) WC2 Humans and Orcs are very similar. There's minor differences but each unit has a directly equivalent opposite number in the other race. In SC, the races are fundamentally different, and play differently. As far as the game engine is concerned, SC being set in space with aliens is totally irreverent. That's just sounds and graphics, SC1 really was the next WC2.   

Of course, as we know, WC3 is a great steaming turd sandwich with a really sweet editor and mass of over-produced graphics. LOL... Ok maybe that's just my opinion. I'd certainly never suggest that Blizz was dumbing it down to point and click fun for the whole family, while they were all still high on the fumes from the mega-gazillion bucks they made from D2. I would never suggest such a thing as I have far too much respect for their visionary awesomeness... and in the end they woke up and redeemed themselves somewhat with SC2. At least it's a genuine RTS.

But I'm a Tolkien Nerd Goddamnit! The Nerd-Gods owe me a nice, shiny, new, awesome, challenging RTS with freakin' wizards and ogres and castles and guys with swords and orc hoards and all dat – because no matter how good the game may or may not be, there's an itch that some freak show of creepy-crawley space critters just does NOT scratch.   

Lambchops looks around and suddenly realises he's standing on a soapbox delivering some kind of weird sermon to a handful of  people at the local pub who's various reactions range from bemused indifference, through wondering if they should be concerned, to actually dialing 9-1 and waiting with their finger above the 1 key just in case this loony is about to totally lose it.

...Oh! ..Um ..... yes where was I? Expanded client features.... >8 players .. Ok, got it. Yeah really needs a complete re-write of the engine for this – even the guys who wrote it in the first place, with their own source code, when expanding it with entirely new races didn't mess with that limit... as far as I can remember, not having even seen SC1 in at least a decade....  and of course the Koreans hacked the living daylights out of it – I mean those guys went totally nuts on it, they even had full on bot leagues where their AIs could compete against each other, but I've never heard of a >8 player game... maybe there is, if anyone knows of this please let me know, but for this WC2 engine.. nah. There was a discussion on THIS (http://forum.war2.ru/index.php/topic,2411.msg45694.html#msg45694) thread with some more info.

As far as maps larger than 128x128, this too would require some modification to the executable, although I don't think it would be anywhere near as difficult as >8 players (which is pretty much a "complete ground-up rewrite" situation) it would still require a considerable amount of time and effort to track down, and I am of the opinion that should the availability of such time present itself, it would be put to better use developing new solutions rather than endlessly tinkering with with a chunk of 20 year old code that we will never be able to really get what we want out of for 2 very pertinent reasons:

      (1) We do not, nor will we ever conceivably own the software nor even the right to use it in the manner we wish to.

      (2) As a result we will never have access to the source code, which is the only way to effect any serious development of a software engineering project.

Even if we collectively spent the remainder of the very brief time we have on this earth painstakingly picking apart every part of the WC2 files the resultant archive of tricks and kludges would still never compare to an active, developing, well written set of source files, and furthermore we would all be too senile to appreciate the collection of kludgey little tricks we had reaped as the reward for our life's labors.

... and to put it into context people, we may all be a touch OCD about our beloved WC2 (myself no less that anyone) but these files we could spend the rest of our lives pawing over are the product of the active, well written source files that the embryonic Blizzard team developed from the ground up inside the single calendar year of 1996.  :-[

So what am I saying? We should all give up and go back to playing tiddly-winks? Hell NO! I'm saying we should get real about this stuff.

Despite the things we can't do with the .exe, IMHO there are some really cool features that COULD be implemented by a new front end using the existing client game engine as a mule of sorts.

        Lengthy rant about Lamby's pipe dreams for a new client front-end clipped and placed in following post due to forum size restrictions.
 
Check it out if you like crazy ideas ;)


If we were to be able to develop a new front end anything like the one I imagine we possibly could(see next post) it would bring in new interest, and revitalize our community (including, and perhaps specifically, the development community), and I believe it would be used by the existing players also, because it would quite genuinely be a better interface.

So if that works, and it's good, and it's used.... because it's good, then that is something real that we have and can build on. Then we could work on a new back-end, then in a later release of the front-end include an option to use the new extended game engine.... which we could, of course, configure to use whatever sized maps and however many players we wanted (or could technically achieve). If its good, people will use it. If its crap or it doesn't feel right, they won't.

I installed Wargus years ago and messed around with it a bit. I didn't like it.
I thought it was a really well written, excellent piece of work. But hated playing it...

... and I have always loved any computer game that had a little guy with a sword that you could make walk around the screen, right the way from the rudimentary text-based graphics in the Ultima series on an Apple ][  in the early 80's, I'm a total junkie for them.

I remember once spending about a week playing some totally tragic freeware Mysterious "Castle" / "Dungeon" game that fitted on a single floppy disk and I think was made by 1 guy living in his Mum's basement. He did it all including drawing all the graphics himself... and it was bad... lol so bad, and it looked worse, and I knew it, but still, I played the crap out of it, stayed up all night more than once.... and I still remember that crappy little POS game over 20 years later! OMG WTH is wrong with me?!  ;D :'( ;D

But Wargus. No way. Couldn't cope with it, and it's a really nice piece of work... Why? Because it looked a lot like my beloved WC2, but it just didn't feel right. It was like fingernails on a chalkboard.

Who knows, if we all had have been introduced to Wargus first, maybe we would all love it and if someone wanted use to use the Blizzard client we'd all go, "EWW". But that's not what happened. So this is the real challenge, to improve what we've got, while still making it feel right.

This is why I think the ONLY way to go, initially, with a new interface is to just use it to drive the existing client, that way as long as we do a good enough job of it, it will still feel like WC2, because people will still be playing WC2. If they want to, people will still be able to play with the Blizzard interface in the same games as  people using a the new interface. Then if its good and people use it we have the ideal environment to develop and refine a new back-end where we can compare it side be side with the existing back-end, using exactly the same interface, and make it so it has all the traits we like but can also use huge maps, and never get a dead spot....  and everything else you ever wished you could fix.

But the real awesomeness would begin when we finally got to the stage where we could introduce a new map format and editor that could handle triggers and events etc., like the war3 or sc2 systems. Once you're working with your own code and not trying to dury-rig little bits of crap into someone else's executable you can do all that stuff.

But for any of this to work, it has to be good, and it has to be optional. There always has to be the ability to make and play standard WC2 games, and the option to play with extended features. That way if they're good, people will choose to use them, if not, they wont. But even if this idea actually turned out better and was more widely successful than we ever imagined it would be and pretty much everyone chose to spend most of their gaming time using the "new stuff", we would still always want to be able to go back and play an awesome game of oldskool-kewl WC2 every once in a while. Hell I would demand that - 'aint nobody takin my WC2 away, don't even think about it!

Oh.... Incos, ..... HI  :D  That's right. What were we discussing? Ahh that's right, editing unit graphics and/or palette entries. Well. From what I understand of the whole black-to-pink mod, its an edit of the data files, not the exe itself.

All the graphics and heaps of other resources are all stored in the mpq files.

MoPaQ

MPQ is a Blizzard proprietary cabinet format. It's short for MoPaQ. The "MO" is the author's initials, it was originally conceived by a guy named Mike O'Brien, and "paq" is just "pack". An mpq is like an archive that can contain hundreds of different files, compressed and organised into an internal directory structure.... kind of like ZIP file containing a whole bunch of different files and folders, except mpq's also have another key feature which is a quite sophisticated hashed indexing system that allows for extremely fast lookup and location and retrieval of an individual resource in a large archive.

All the game data and resources initially existed in war2dat.mpq, but IIRC the system is set up so that entries with the same name/internal path in war2patch.mpq will override the default files in war2dat.mpq, in this way blizzard could release various patches and upgrades, just by adding them to the much smaller war2patch.mpq instead  of having to reproduce and distribute the entire wad of resources for most of the game that is war2dat.mpq.

Despite being a proprietary format that has never been technically available to the public, quite a number of MPQ readers/editor have been written by third parties over the years (generally gaming enthusiasts), however Blizzard continued to use MoPaQ for many years after WC2, and they also altered and updated the specs for the the internal file structure many times along the way. Certainly WC2, SC1, WC3, D2,D3,WoW and I'm pretty sure also SC2 all use various versions of MoPaQ, and they all have the same ".mpq" file extension.

 As a result many if not all of the 3rd party MoPaQ tools tend to only work with a small subset of MoPaQ versions and therefore you need to have the right editor to open the mpq files from any particular Blizzard game. So in the case of WC2, an old one... at least that's the way it used to be, I don't know if anyone has written a more comprehensive mpq editor recently, at any rate EasyCompany is the guy to talk to about that stuff, he's much more clued up about it than me... I'm a bit of a code monkey, when I'm messing round with graphics resources it's because I've pulled them out of process memory, not the mpq files.

BTW: I think it was only last year or the year before Blizzard finally introduced its new container format, the successor to MoPaQ. Was big news for nerdy folk like me.... lol.

Pink OGRES

As far as how the pink ogres thing actually works, I don't really know, because I've never looked at it. I did have it installed on a version of war2ce a while back, but I've never looked at the internals or mechanism. That being said, however, I would be extremely surprised if it worked in any way other than replacing the 0xE4 to 0xE7 palette entries with shades of pink as against shades of grey/black.

GRP

The WC2 unit graphics are stored in a format called GRP. IIRC the GRP files are stored in war2dat.mpq then loaded into process memory when WC2 starts up.

GRP is a pretty interesting format, but I won't describe beyond saying that GRP is short for “Group” and they indeed then to contain groups of related images – in this case the various images that are used to animate the on screen unit images. Any further description isn't needed as I've actually written a pdf doc explaining the internals and implementation of GRP files in WC2 which I will attach to this post. The only other info on their internals I have come across was a text file written about 15 years ago by someone who had partially worked out how to decode them but still didn't understand some of the principles, it was however a useful starting point.

Certainly I can tell you that in the normal scheme of things, there is only ever 1 copy of each GRP in process memory. The unmodified GRP frames are all for the red player (player 1 when fixed order – or actually player 0 internally). As I understand it, the only time that images of other colored units are produced is when each frame is actually being rendered onto the screen display buffer, at which point as i decodes and renders the current frame for each on screen unit, the GRP decoder substitutes the palette indices for entries 0xD0 to 0xD3 with the appropriate entries for the color that has been assigned to the player that owns it.

I don't know if the palettes are stored in war2dat.mpq then loaded (which seems likely), however as they are not particularly large amounts of data, they could be already resident in the executable's '.data' section, but could be overwritten by a particular entry in war2patch.mpq, so the black to pink mod could be a direct edit of war2dat.mpq, or entry added to war2Patch.mpq that overrides the original palette in either war2dat.mpq or the .exe. It could also even be an edit of the palette in process memory after WC2 has loaded, but I think I remember reading/hearing somewhere that it was an mpq edit of some sort.

Anyway, as far as editing graphics and mpq's and the like, as far as I know EC is da man. :)





DOGGIE BAG


If anyone is interested I documented the GRP format which is an the attached pdf.
   ( there's even some nice pretty pictures if you don't want to read about it ;) )

Also, while we're on the subject of palettes, I've attached a basic little app for displaying the palette from 8 bit PCX files ( i.e. wc2 SS )
....Just drop a SS on it and it will produce a small bitmap file that has a 16x16 grid of colored squares on it that show the 256 colors in the PCX image's palette... Something like this:
(https://i.imgur.com/LLdvE72.png)

Title: Re: Nerd's Corner
Post by: Incos on March 01, 2017, 08:03:02 PM
Intense writeup as usual. Yes I edited the wardat.mpq and extracted the separate grps into an edit folder. I than changed the peon004 image to use green instead of black in the palette. I then used grp edit, loaded the peon grp, deleted the frame 4 and replaced with my new frame 4 with green over black. I save tried to play and gave me error... the thing is, the war2patch file is the only one downloaded through the change. So I'm not sure if it's more of a .ppl file which I have no editor for or if it's maybe a table file(which I thought was only for text like campaign or bnet graphic changes) unless it's simply in the forest file?? Which is also changed in the black to pink war2patch, in that case o would have to edit the tile palette...

And yes im obsessed.and I do like the trigger ideas, the game could develop further in the custom games that way. 
 
Title: Re: Nerd's Corner
Post by: Lambchops on March 01, 2017, 08:26:05 PM
A New Face For Warcraft II
Pipe Dreams of a Madman/Black Sheep

This is, at the moment, nothing but fantasy. But as fantasy goes, at least it can be defined under the heading of “Science-Fiction”, because I'm confident that the following is all, at least technically possible using the existing game engine with only minor peripheral mods, as to whether or not any crusty old gamers ever get their stuff in a pile and actually do any of it, that remains to be seen.

I have been scheming about this for a while now, and the sorts of things that are possible are pretty cool. Here's what I imagine, and bear in mind I haven't  got anywhere near even considering when to start thinking about starting to work on such a thing yet, and when and if that ever happens it will likely take a long time to complete, but I'm starting to picture something like this:

So imagine the interface is hi-res (obviously) and the game window (aka -by me – viewport) which is currently a fixed 14x14 grid of 32x32 pixel tiles, can be zoomed in and out with the mouse-wheel so it displays as little or as much of the map as the player desires. It can also be resized – perhaps with holding the left button while you mouse-wheel or some-such to be any size you want, you could even zoom right out until the entire map is displayed, then resize it down to a small square, so it becomes just like the mini-map – in fact, the mini map is just another viewport, they are the same... BUT..  now lets add another level ... 

   You start a GOW game. You spawn at 9, drop a hall, a farm then head straight for 11 to wreak havoc with GTs and whatever else you can come up with.... and at the same time (of course) the player at 11 is doing the same thing to you. Most of us are familiar with this situation to some degree... so, now picture it on a widescreen monitor. You look at 9 to defend your base, then you need to go back to 11 to keep attacking, but instead of clicking on the mini-map to shift your viewport back to 11, you click on 11 on the mini-map but hold the button  and drag the mini-map down into the main interface area. Now you have 2 viewports open side by side. One showing 9 one showing 11. You can select a unit in one viewport and target in the other, you can open a 3rd and resize it to be just a small one in the corner to keep an eye on the smith that's blocking off S9, and just leave that there.

   But perhaps you started at 2 and there's a pard at 12. At this stage your enemies are not attacking your base, so you are rushing grunts for support and trying to power as fast as you can at the same time, but your other pard at 6 is getting hammered by all the enemies that aren't attacking you. At the same time you know that the enemy at 11 got messed with pretty badly by your other pard at 9, so you want to take advantage of that and attack him while he's weak.. IDK you tell me?... I imagine I might have a my base at 2 in a large window covering like half the widescreen, then a smaller view of 6 because you're having to send grunts there to help out, and perhaps even a little viewport showing the area below S9 so you can rally you grunts there before sending the on to 6. Maybe another small window showing the entrance to 11 where the guys at 9 and 12 are giving him hell, but his pard at 4 is helping him. 

   So you are building farms... upping your smith, pumping out peons and grunts on you main viewport, so your grunts pop and you select the 6 grunts that are there then right click where you want them on the window displaying the area below S9 at the same time there's a few more grunts already rallied there so You select them and punt them down to 6 where the enemy at 5 is attacking... Sure you can already target units using the mini-map.. still can if you want, but on the mini-map u cant tell if a passing enemy unit is a peon or a DK, or see whats attacking you or even select your ogres and lust them and you can't select units on the mini-map, on a small viewport, you could. Suddenly your rallied grunts are attacked by a group of enemies.. you grab that window with the mouse.. just click and drag and throw it up into the top right corner of the monitor. Instantly that is full screen and you can manage that battle.... or if you wanted, you could click the mini-map oldskool-style and shift you current base view to that location as per the way things are now, it would depend on your own style.

   That little battle plays itself out and 15 seconds later you are back at you base building etc. When you notice on the little 11 viewport you have in the corner of your monitor that 9 and 12 have almost broken into 11 but their attacking force is almost dead so you immediately send your first ogres that have just popped to finish the job, selecting them in your main base viewport and targeting them at the failing enemy rax on the 11 viewport. Meanwhile 6 has died you no longer need the view of 6 and your rally point, so you grab each of them with the mouse and throw them at the bottom right corner of the screen (the trashcan, if you will) and those views are disposed of, leaving u space to grab 3 from the mini-map and drag it out to create a new view there while you establish an exp.

This is an interface that could be left as absolutely standard WC2  as it is now, or just higher res with a bigger display or customised to have any number of different views of different parts of the map, each of which could be used to select, target or manipulate units, its up to the individual player how they want to use it. Of course the fog of war would still apply so if you don't have vision you just get a black or greyed-out view as per normal

I think saving/restoring the configuration of viewports would have to be limited to in-game only, i.e. I don't think it would be in the interests of game-play for people to be able to pre-configure bunch of tiny views showing, for example, the exact spot where a peon would stand to be in the top left corner of a tower underneath the mine at 9... then all someone would have to right from game start would be target a peon at this little window with a single click and wait for it to walk to that exact spot and the instant it gets there grab it and [B|T]. I think the setup and manipulation of any viewports would have to be part of the player's skill in an individual game, like accurately sending a peon from 8 to S9 at game start, however once any particular set of views is established in a game, the player should be able to save and restore that configuration; perhaps with CTRL-F1 --> F8 similarly to how groups are assigned and selected.

The interface controls, be they keys, buttons or even tablet-like “gestures” with the mouse would have to be thoroughly play-tested for the base set, but should also be customisable to suit individual taste/style.

I believe an interface like this would bring attention and an expanded player base to the WC2 community.

In the same vein, it would be incidental to creating this interface to be able to exceed current limitations for grouping/commanding units, i.e. There would be no technical limit on the number of units you could select at once, and issue any command to for example spells etc. Obviously there would have to be some limit applied, and this is something that would have to be looked at very carefully to avoid upsetting the balance of the game, however my thinking is that some increase might be beneficial. I am inclined to believe that the current 9 unit limit was more defined by the available screen area for displaying unit portraits etc. circa 1996, than it was by any game balance issue. Perhaps 12? 15? 20? this would have to be tested and evaluated.

The multi-casting commands should probably be updated. Of the 2 methods currently available I'm reasonably sure that only a handful of players even know that the second, and more effective method exists, and it's such a tricky combination to pull-off in the heat of battle that there are very few players who can effectively use it, so formalising and standardising this might be appropriate... however by the same token we don't want every noob and his dog wandering around with 20 mages multi-blizzarding bases to rubble... so: test.. balance...test...balance...

... and the other thing that keeps tickling the back of my brain is a ripper. It's a whole extra technical layer of programming, requiring the new clients to set up an independent ancillary channel of network communication with each other, but once that is done, there is no reason why we couldn't have shared control of units.

So if you have a good pard that you trust, who is effectively out of the game, say because their base has been wiped out and they don't have enough gold to build a hall, then you could grant them shared control over your units.. so perhaps you are managing your base, building, producing  units and sending them to battle at whatever locations, while your pard micro-manages your melee units on the front line in battle. This would lead to custom maps made like “watcher” style maps where 4 teams of 2 people could compete executing strats they have drilled as a team or even 2 teams of 4 people.. lol that could become totally insane.

The other thing that this could possibly lead to is.... the very thing that I have just gone to great lengths to tell you can't be done; more than 8 players in a game. Of course they wouldn't actually be “in the game”, as far as the WC2 engine is concerned, there would only ever be <=8 players in a game, but allowing additional players control of units could possibly extend to players that aren't even actually “in” the game being able to take part in the game-play, so for instance 8 teams of 2 or even 3 people going head-to-head. The game engine would still see it as 4v4, but there could be, for instance, 24 people controlling the units.

This would, however require yet another technical layer, in that the additional players would be outside the game engine's loop, indeed they wouldn't even need to be running WC2 at all, only the new front end, and they would be totally dependent on the actual “in game” player to provide them with the entire game state, all units... positions.. actions.. chat messages, everything, via the ancillary network link. This is a lot more information than just issuing a few commands. It could induce lag in poor connections, or it could possibly even reduce lag by having the connection between the endpoints re-prioritised by various servers in their connecting route, there are so many possible factors that it would be futile to attempt to predict the results before an implementation is attempted and at least alpha-tested.

If  -  and it is so very definitely IF – no promises for even the simplest of the fantasies presented herein, and this is as far as it gets from the simplest – but IF that could be achieved, and the work completed some time before my 98th birthday, then a reasonably simple to implement follow on from that would be virtually unlimited watchers. Only one player would have to send the feed of the current game state to a watcher (although in practice you would probably send multiple feeds for redundancy in case of network interruption) and from there the watchers could disseminate the feed to each other, and view it on the client front-end which would construct  and display it as if the watcher were in the game.

This stuff all has a whole bag of potential issues attached to it, of course. For starters, I think at least a 30 second delay would have to be inserted into the “watcher” feed to minimise the potential damage that could be caused by an unscrupulous player running a second front end on another machine, registering this as a “watcher” then using it as a form of map-hack.

Then there's the whole “last farm” issue. At the moment if someone is effectively dead but still has a surviving unit somewhere the remaining enemy players will usually leave the “last farm” or whatever alone to allow the “dead” player to continue to watch the rest of the game. If however, there is a very real advantage to be gained by by the other team while that player remains in the game... because they can improve the effectiveness on their teammates' attacks by micro-managing their front line units in battle, and whatever else, then players would probably start instantly killing everyone's “last farm” at the first opportunity. 

There are a few possible solutions to this: a control could be added to the front end whereby a player could declare themselves to be officially “dead”. All players would be made aware of this and once this option was used the relevant player could not, thereafter be involved in the shared control of units. If the full game-state feed suggested above could be implemented, it could automatically be used to allow dead players to continue to watch the rest of the game, thereby making it irrelevant if their “last farm” is killed or not.

It could also lead to some potentially fun scenarios where a player's last remaining peon is hiding in their pard's base while they assist with shared unit control, but thereby making the peon a high-priority target. This situation could lead to enemies actively searching for and attempting to assassinate the player's last remaining unit(s).

There's also the issue of potentially having to kill the same pro player 4 times over to win a game, which could possibly lead to even more noob-bashing that already occurs now. Consider a team of 4 players:

      W0ND3R!W0M4N, who is the super-pro player of legend who is so skilled that she is spoken about in reverent tones even in private chat channels on Farmville.

      [XL]Stinky, who was never even in [XL] in the first place, he's just a semi-skilled poser who tries to convince everyone he's totally awesome when he's obviously totally average, and very annoying.

     MERC_BEANZ, who is an old WC2 player from the battlenet glory days who has recently found server.ru and has been enjoying some games over the last couple of weeks. He's having fun but still has a bit of a way to go to catch up to the skill level of the better players around.

     Lambchops, who is a total noob with no clue and why do we even let him play?


Ok, now for this game their opponents are pretty strong, say 2 “good” players and 2 “decent” players, no real noobs. Now if they're smart they might realize that Lambchops and MERC are both no real threat until they've had a 20 minute head start. Stinky's not a big issue either, being not quite as good as either of their “decent” players. So they have options here, they can attack and easily pick off MERC and Lamb, Stinky will put up a bit of a fight, but won't really be an issue either, but the problem is that by the time they're 3/4 of the way through doing this, the behemoth that is the  W0ND3R!W0M4N war machine will have started rolling and they will be up to their armpits lusting amazonian ogres pounding   buildings flat, tearing down towers, and picking up peons by the ankles then thrashing them to death on their altar of storms. Not a good scene, in fact really scary stuff.

On the other hand, if they're clever they will realise that at the start of the game they can send one of their “decent” players to attack stinky, at least occupying, if not killing him, and they can pretty much ignore Lamb and MERC who will still be trying to work out why they're out of lumber for another 10 minutes, then they can send their best 3 players to all rush  W0ND3R!W0M4N and overwhelm her before she ever gets a chance to get properly set-up, then once  W0ND3R!W0M4N is out of the game, they can pick off the remaining noobage at will.
Good plan. Except wait. Now  W0ND3R!W0M4N and “help” Lambchops control his units. At this point W0ND3R!W0M4N strides into Lamby's base, bitch-slaps him to the ground and and snaps, “Go sit in the corner and keep you're mouth shut”. “Yes Ma'am”, says Lambchops, and now  W0ND3R!W0M4N is back in action. Depending on how badly Lamby has messed things up, it might not take her long at all to get back on track and pwn the entire map. Or if the other team sees what's going on then immediately triples “Lambchops” - now actually  W0ND3R!W0M4N, shortly afterwards  W0ND3R!W0M4N will be seen striding into  MERC's base, and on it goes.

The other team may be able to keep it up, maybe they will end up getting overrun, but they aren't really supposed to be fighting the one player 4 times over, and it also removes a lot of the incentive for the other team to try attacking a strong opponent at game start, really it lends itself to more to the “pick off the weakest noob first” ethos.

So, perhaps to avoid these kind of problems there could be a 2 different “shared control” modes, equal control of all units, for “team control” games where 2 or more players start the game collaborating, and “assist” mode which allows a “dead” player to control another player's units (if they allow it), EXCEPT for peons. So the building, resource gathering, repairing etc. must always be done by the original player, but the assisting player can still control melee units, pump more out of rax, etc.

OK?

Cool.

 So who wants to make it happen? 1-2-3-GO!

What? Me?... Awww C'mon fellers I just did the 1-byte no-math mini-map patch, must be someone else's turn to do this one...

OK. Fine. I'll definately start it sometime in the next 10 years and finish it some time in the next 80 ... Ok?
lol knowing me I'll probably start after lunch... who knows?  ;D


It should be noted that the concept for this game interface is the original work of Lambchops, and is (c)Copyright 2017 Lambchops, being the person identifying themselves as such on the Warcraft II Forum, which is currently, being the 2nd of March, 2017, hosted at forum.war2.ru, and noting that this person is an Australian male currently 46 years old and residing in Queensland, Australia. Should any software producer wish to implement any of the ideas or designs described in this document, they are urged to contact the author before proceeding as he really doesn't want much more than to be part of the team that implements them, and he's actually quite a useful coder.  :)  HI 




Title: Re: Nerd's Corner
Post by: shesycompany on March 01, 2017, 09:01:18 PM
this is the .ppl ..i have to go thru the order again sometime.....it can turn tress, land etc to a solid color...helps performance boost old machines.
(and i mean like a 386-25)
it can chang color of the mini map units and units but it is very wierd...like blackish redish blue etc...

(http://imagizer.imageshack.us/v2/516x387q90/924/XsBMFj.jpg)


its kinda like (00 00 00) RGB? html colorchart worked for my colors ...

conclusion .ppl's is pretty good for changing tiles colors ..instead of having to create them.

now back to lamb ..im reading it man got my high hoped up beer, it will more than likely slow my brain down...if not ill put in some added music!
---------------------------------------------------------------------------------
"""... and the other thing that keeps tickling the back of my brain is a ripper. It's a whole extra technical layer of programming, requiring the new clients to set up an independent ancillary channel of network communication with each other, but once that is done, there is no reason why we couldn't have shared control of units."""
  :o omg man
Title: Re: Nerd's Corner
Post by: Lambchops on March 01, 2017, 09:50:40 PM
Intense writeup as usual. Yes I edited the wardat.mpq and extracted the separate grps into an edit folder. I than changed the peon004 image to use green instead of black in the palette. I then used grp edit, loaded the peon grp, deleted the frame 4 and replaced with my new frame 4 with green over black. I save tried to play and gave me error... the thing is, the war2patch file is the only one downloaded through the change. So I'm not sure if it's more of a .ppl file which I have no editor for or if it's maybe a table file(which I thought was only for text like campaign or bnet graphic changes) unless it's simply in the forest file?? Which is also changed in the black to pink war2patch, in that case o would have to edit the tile palette...

And yes im obsessed.and I do like the trigger ideas, the game could develop further in the custom games that way. 

Hey Buddy,
Sorry, took me ages to get all that stuff posted.... and oh hey of course - we're all obsessed, that's why we're all still here tinkering with this thing lol, but I certianly wouldn't have thought anything at all about you from your post other than you're a guy who is interested in graphics mods. Really, as I noted at the top, the most of that post was nothing at all to do with you personally. These discussions about a new font end and client mods have been going on for some time now and I've been spending some time thinking about the possible outcomes that could realisticly be achieved. In a modular sense. So we're not trying to achieve the impossible and never getting a result... but I thought I might try to fire people's imaginations about how far we could actually take this if we got serious.

But breaking it down, step 1 is driving the existing client from an external source, and developing a screen renderer that can produce arbitrary views of the game. At this point we only have to write some basic interface stuff: selecting things by clicking on them, by dragging a box around them, issuing commands with the mouse, checking the keyboard and cross-referencing the keypresses with the currently active command panel hotkeys... blah blah blah... and then drive the game engine to execute those commands.

At this point we have, if nothing more, a hi-res front end for wc2, which is something.
... and the real point is, once we have that done, if we can render one view of the game, then we can render 10, because it's our code, not a crude hack of someone else's exe.

So at that point the multiple viewport interface i described is not very far away at all, in fact at that point we would have already coded all of the main components that would be needed to produce it.

---------------------------------------------------------------------------------------------

Now as far as your graphics editing goes, I'm afraid I may be of little use. I am not familiar with the tools you are using, and to be perfectly honest, using a bunch of of amateur written apps (which, regardless of how good they may actually be, all fit into a box in my head labelled "work's partially, some of the time") to try to edit a collection of datafiles I don't completely understand, sounds like what I would find in the room purpose built to be my own personal hell, should Santa ever see fit to put me on the naughty-list.... so I try really hard to be good :)

anyway... i think EC said something about .ppl files a while back and the conversation at the time was about palettes. Also I note, just pulling the mpq content paths and filenames from the running wc2 process Swamp.ppl, Forest.ppl and Wasteland.ppl (but no Winter.ppl). Perhaps winter is the default, or perhaps it hasn't been dynamically loaded because I haven't played a winter map since I started the WC2 client today.... idk.

However my suspicion is that these files containing palette entries.

Tell me are they exactly 768bytes long?    or perhaps 1024bytes?
If so I would take this as confirmation ...........  If not then IDK

-----

But if they are, then if you want to edit the palette entries you can do it with a hex editor, if you know what you want to do.

There are 256 palette entries in an 8 bit palette. Each entry will consist of either 3 or 4 bytes.

... if the file is length 768 they are 3 byte entries
                   if len: 1024, they are 4 byte entries (or an "RGBQUAD")

So the first 3 bytes will correspond to the intensities of RED, GREEN, and BLUE in the color for that palette entry. The will be values between 00 and FF in a hex editor (0 and 255) in decimal.

if they are 4 byte entries, then the 4th byte in each entry is the "Alpha" channel which designates the overall intensity of the color, but in many cases, and I would expect in an app as old as wc2 this 4th byte is just always set to 0 and ignored. The main thing are the R,G,B values.

SO:

FF,FF,FF  = bright white
00,00,00 = black

88,00,00 = red
FF,00,00 = brighter red
30,00,00 = dark red
00,00,90 = blue
00,FF,00 = bright green
80,00,80 = some purple     (red+blue=purp)
etc...
         .... its how bright the RED,GREEN,BLUE is for each color

** SOMETIMES, particularly for quads, you may find that each entry is stored in reverse order:
          i.e.       B, G, R
           or   A, B, G, R
if you're going to mess around with them you will quickly discover if they are reversed.

Also, please note that the first entry  i.e. the first 3 or 4 bytes is Entry 0
                                                           the next 3 or 4 bytes is Entry 1 .... etc.

Will try to help with other stuff later, but really gtg right now
going to be late for an appt.
HF
 :)


(EDIT:  This discussion led me to investigate .ppl files then make the palette editor (below). In doing so I discovered that the RGB color values  that Blizzard decided to save in its .ppl files aren't values from 0 --> 255 like normal 8 bit palette entries, for some reason they have used values of 0 --> 63. IDK why. Perhaps as a way of standardizing color values among a team of graphic artists who were using very similar but slightly different shades. That's just conjecture, but the end result is: to convert a .ppl palette to a standard 8 bit palette you have to multiply the R,G and B values by 4.... and of course divide by 4 when going back the other way)

Title: Re: Nerd's Corner
Post by: shesycompany on March 01, 2017, 10:13:56 PM
go cool off them thoughts  ;D gl hf!


edited the .pal but for some reason it didnt stick....
http://imagizer.imageshack.com/img924/4285/mf6byL.th.jpg (http://imagizer.imageshack.com/img924/4285/mf6byL.jpg)

so maybe these colors are still called at the start ,dont know cheers!

just use lambs patch or the other one...the colors that do stay are all the other colors of the .pal
so lamb is in the right place!

but u can still do this!!

http://imageshack.com/i/pmB3f7QHj (http://imageshack.com/i/pmB3f7QHj)

the green flashes orange lol its kinda comical!

but if your just dying to...all buildings have to be enlarged canvas to 128x128..with out a automated macro or a program, unit creation is to much to bear...

but to fill it in even more... after we got our macro in place to make for you...i got one that will doit....

u got to go to the web or wherever make/or get  a sprite sheet...pal it..prep it so it will have team colors..and no flashing unwanted colors thus editing the pal to the sprite sheet.

then your ready!

its not that hard.

and i got a swamp.pal that i edited at the start..its 99% finished..which means any sprite u .pal will look almost like it. from donkey kong to idk a rainbow zelda ..

and with exe..pud edits u could bring in...warcraft1 units, starcraft units etc 3 races impossible? no thought of the way around of it with a simplier approach mirror exe's.

and also red alert loool i still like that game hate the engine

:o dude can jump in if he wants taking over this game is just what u make of it
Title: Re: Nerd's Corner
Post by: Lambchops on March 02, 2017, 04:57:41 AM
but u can still do this!!

OMG man!             
PIMP MY MILL!

I LOVE that show...  who dobbed u in?

Did they really just roll up unannounced at your great hall or was it staged?  ;D
Title: Re: Nerd's Corner
Post by: shesycompany on March 02, 2017, 05:15:12 AM
take your ass to bed!
Title: Re: Nerd's Corner
Post by: Lambchops on March 02, 2017, 06:06:18 AM
take your ass to bed!

Ye. Been 3 days (oops).
Thx for noticing.

But I deserve a couple of games first. Spent most of the last 24 hours writing, until a had to go to an appointment just after lunch, nearly made it too - but then my crappy old chunk of car blew a head gasket. Like BIG TIME... like blowing the smokey exhaust directly out of the radiator big-time  :'(

Title: Re: Nerd's Corner
Post by: Incos on March 02, 2017, 11:38:21 AM
So you need to make a sheet up for the animation file. And it's restricted to 8 bit 64 colors?

Thought you could string images together in a grp file. I imagine the parameters would include a transparent background as obvious.  I like the green mill haha.
It seems really simple to me, i use to mess with bullletin board systems and the text games that surround but for the love of me can't implant a character in Warcraft 2.

Imagine it's more complex than just replacing one frame, like if I wanted a peon with a Mohawk and replace one frame where he has a Mohawk such as walking down. The one dude added the whole dwarf race with the strat engine. I'll tinker today
Title: Re: Nerd's Corner
Post by: shesycompany on March 02, 2017, 03:40:26 PM
car blew a head gasket    :o
Title: Re: Nerd's Corner
Post by: Delete mine too on March 02, 2017, 06:58:06 PM
car blew a head gasket    :o
I hate that my Monte Carlo went out like a champ! The fucker would over heat and I would pull over and put a rag over this metal tube and push a screw driver to release all the air building up. Then I would be good for another day! Sadly I sold that bitch for a grand :, ( the mechanic I sold it to fixed it for like 300 and did 24 hours worth of work :) lucky dude!
Title: Re: Nerd's Corner
Post by: shesycompany on March 03, 2017, 12:49:37 AM
yeah inco.

if your wanting to mess with 2d. this ripper is nice.
http://www.alferdspritesheetunpacker.forkandbeard.co.uk/forkandBeard/apps/AlferdSpritesheetUnpacker/Download.aspx (http://www.alferdspritesheetunpacker.forkandbeard.co.uk/forkandBeard/apps/AlferdSpritesheetUnpacker/Download.aspx)

i do all my sprite sheets then use this..

then use gamemaker ...any of the old ones 7 - 8.1 etc with my macro to resize canvas for all of them.
Title: Re: Nerd's Corner
Post by: Lambchops on March 03, 2017, 02:04:10 AM
So you need to make a sheet up for the animation file. And it's restricted to 8 bit 64 colors?


8 bit = 256 possible colors, although much of the palette in wc2 will change from forest to winter etc. so is inappropriate for units, and as discussed obviously there are 32 entries (4x8 players) reserved for player colors, so 64 colors is probably about right, never actually counted them.

Thought you could string images together in a grp file.


Yes. GRP is actually an abbreviation of "group". There are only a handful of GRP's in WC2 that only have one image (oil patch, runestone, circle of power, dark portal, human and orc start locations) The buildings have 2 frames: half built and complete for each.

Most of the units have quite a few, i.e. the knight/paladin has 70:

(http://ss.war2.ru/ss/9171.gif)

Have a look at my GRP format (http://forum.war2.ru/index.php?action=dlattach;topic=2703.0;attach=1091) pdf.

Title: Re: Nerd's Corner
Post by: Incos on March 03, 2017, 11:50:32 PM
If anyone is interested, its like a hue'd lime green instread of the Pink.
Title: Re: Nerd's Corner
Post by: Lambchops on March 05, 2017, 03:08:42 PM
If anyone is interested, its like a hue'd lime green instread of the Pink.


I'm lovin' your initiative... not so much the lime green ;) so here's something that might help.


(http://ss.war2.ru/ss/9173.gif)


(http://ss.war2.ru/ss/9174.gif)


App attached. Not tested, but seems to work Ok.
Will load a palette from a .ppl, a WC2 SS, or an 8 bit bitmap file. Saves to .ppl

Enjoy  8)

Title: Re: Nerd's Corner
Post by: shesycompany on March 05, 2017, 07:07:10 PM
very cool man!

smurfs!!
http://imagizer.imageshack.us/v2/516x387q90/923/Im3GD2.jpg (http://imagizer.imageshack.us/v2/516x387q90/923/Im3GD2.jpg)
Title: Re: Nerd's Corner
Post by: Lambchops on March 05, 2017, 08:36:25 PM
smurfs!!

Hehe they look like little blue ninjas.  ;D

Glad u like it. Still needs a few things... command line parsing so u can drop a file on the exe, or associate it with .ppl files so u can just double click on them.... and a color spread function so u can make a light color and a dark color then automatically make the shades in between.
Title: Re: Nerd's Corner
Post by: Incos on March 05, 2017, 08:49:08 PM
very cool man, anyway u could add a peasant? =x jw.. if not it cool, i know its code.

Trying to get better at this ripping sprites at the moment. Taking me awhile to get one unit done. Trying to create a demon race.  Might have to delete the human race to have it done though. Not sure if possible to do 3, would have to edit the tables, code. Lots of lining up to do
Title: Re: Nerd's Corner
Post by: Delete mine too on March 05, 2017, 09:53:58 PM
very cool man!

smurfs!!
[url]http://imagizer.imageshack.us/v2/516x387q90/923/Im3GD2.jpg[/url] ([url]http://imagizer.imageshack.us/v2/516x387q90/923/Im3GD2.jpg[/url])

That's freaking cool looking hahaha.
Title: Re: Nerd's Corner
Post by: Lambchops on March 06, 2017, 12:28:46 AM
...so a few hours ago Nedro was asking if I knew how to make a big SS of an entire map, and I felt pretty bad after all those times I killed him while he was watching ;D, so... Challange Accepted.

For a test run I picked the noobiest map I could find, and it turned out something like this:

(http://ss.war2.ru/ss/9176.gif)

Well, actually it turned out like a 16MB 4096x4096 bitmap, which is too big to attach. I tried multi-pass PNG compressing it and the best I could get was a bit over 2MB (still too big), so I ended up attaching a savagely compressed JPG, which unsurprisingly looks pretty bad if you zoom in. The original is game quality, stitched together out of 225 individual screen grabs. Takes about 0.22 seconds to grab the full image then about half a second to save it to disk.  8)

I'll tidy up the program a bit and post it later.
   

Title: Re: Nerd's Corner
Post by: shesycompany on March 06, 2017, 01:53:14 AM
a hold up nedro is a mario kart player!! if it was dellam ok  ;D cool a gow poster!...

(been busy tonight)
actually bought a android laptop thingy  ....was gonna make  war2 play on it but got side tracked .....got my controllers hooked up to it and mario kart going sucesss!!!!!
Title: Re: Nerd's Corner
Post by: Lambchops on March 06, 2017, 02:11:08 AM
....was gonna make  war2 play on it but got side tracked .....got my controllers hooked up to it and mario kart going sucesss!!!!!

WOOOOHOOOOOOOO Yeeeaaahhhh! Now we're talkin! :D I mean WC2 is pretty cool and all, but Mario-Kart Warriors are the truely HARDCORE.

Hehe - anyway. I finished the grabber. If I had more time to spend on it I'd add an option to stamp the image with the time/date and player names etc... some other time. I'll post it now.


Title: Re: Nerd's Corner
Post by: Lambchops on March 06, 2017, 02:21:16 AM
FULL MAP SS GRABBER
So just run the .exe then hit F6 when you're in game.

*Move the cursor off the game window or you'll get bits of the cursor and it's background stuck all over your SS.

*Works in server games, but also in Single Player, so you can "on screen" it and get a full view.

May still have bugs IDK, I just knocked it up this afternoon, but seems to work OK. Let me know if any problems. Enjoy  :fro:


Edit - It just does a quick search for a window with a title starting with "Warcraft II" so close any other open windows with that name - i.e folders etc. or it may think that's the game.

Also somebody just asked me about it working on pause and hackers, etc...  It doesn't work on pause, it needs the game running to move the screen offset and get WC2 to render all the individual pieces that are stitched together to make the full picture.

It is intended to get a big picture of the whole map, it is not intended for catching noobs using map-hacks. For SS challenges you should still post a normal SS.

(EDIT)

Included WC2FullSSc.exe, self checking version should help for people experiencing glitchy results.
Title: Re: Nerd's Corner
Post by: 8)MikulZ(8 on March 06, 2017, 09:20:11 AM
Avira reports a false positive "TR/Crypt.ULPM.Gen" with your ss grabber can you do something about it? :D
Title: Re: Nerd's Corner
Post by: shesycompany on March 06, 2017, 09:22:29 AM
probably thinks its a keyboard logger.
Title: Re: Nerd's Corner
Post by: Lambchops on March 06, 2017, 01:46:33 PM
Avira reports a false positive "TR/Crypt.ULPM.Gen" with your ss grabber can you do something about it? :D


Not really mate, sorry.

Some AV or another will almost always make some crap up about any .exe file that hasn't been digitally signed by paying big$ to one of the official money makers.

All I can do is give you my personal assurance as someone with whom you have spent a fair bit of time, and someone that has (as can be seen by this thread - and my other posts on this forum and the old one ) devoted a decent chunk of his life to being involved with the community, that I personally compiled it less than 8 hours ago from source code that I wrote myself and I am absolutely sure that it is 100% safe.

But thanks for letting me know. I have noted, of course, that you state that it is a false positive, and I know that you are an intelligent guy, and your query is about getting rid of the warning.

I have still (as I tend to lol) written a rather lengthy post about the issues that come with AV software, not necessarily for yourself, but more for anyone else that gets some kind of AV response and has concerns.

So open if you dare! LOL

Anti-Virus False Positives ---> 
Spoiler
EC has a point, in that it calls GetAsyncKeyState to check the F6 key to so it knows when to take the SS. GetAsyncKeyState is a Windows API function that (obviously) checks if a key is being pressed or not, as such it can also be used for key-logging - if you use it to track the state of all keys then save them.

This is superficially analogous to saying that a tyre-iron can be used to beat someone to death, therefore we should suspect that anyone with a tyre-iron is a murderer. Of course most people have one in their trunk and just use it when they have a flat tyre.

The main point here is that you don't sell AV software by not reporting anything. Sadly most people believe that if AV#2 "finds more stuff" than AV#1, then AV#2 is therefore more sophisticated, and more secure.

Bloggers do comparative tests feeding a heap of different AV suits everything from actual malware to stuff that some other source said was a "PUP" (potentially unwanted program). Often they copy the descriptions of these things from the websites of the people selling the AV software to sound knowledgeable despite understanding very little of what they are writing. As a result, many AV providers got scared not to report EVERYTHING, in case they looked ineffetive on some moron's blog page.

It's a massive industry worth $Billions, and their competition has traditionally been one of providing the most alerts.... although they are slowly gettting better as the population becomes more tech-savvy. I always have a lol when I see the results of a multi-AV scan and they are all saying a different thing... or an identical thing. For instance: here's the results for that file from VirusTotal.com - it's a useful site that checks just about every available AV resource.

Code: [Select]
Avira (no cloud)        TR/Crypt.ULPM.Gen               20170306
Arcabit                     Trojan.Heur.emGfXPgbohm     20170306
BitDefender             Gen:Trojan.Heur.emGfXPgbohm     20170306
Emsisoft                Gen:Trojan.Heur.emGfXPgbohm (B) 20170306
F-Secure                Gen:Trojan.Heur.emGfXPgbohm     20170306
GData                   Gen:Trojan.Heur.emGfXPgbohm     20170306
eScan                   Gen:Trojan.Heur.emGfXPgbohm     20170306

Endgame                 malicious (high confidence)     20170222
CrowdStrike Falcon (ML) malicious_confidence_68% (D)    20170130

Invincea                worm.win32.bartly.a     20170203
McAfee-GW-Edition       BehavesLike.Win32.Sality.lc     20170306
Qihoo-360               HEUR/QVM18.1.0000.Malware.Gen   20170306
TheHacker               Posible_Worm32  20170305
ALYac 20170306
AVG 20170306
AVware 20170306
AegisLab 20170306
AhnLab-V3 20170306
Alibaba 20170228
Antiy-AVL 20170306
Avast 20170306
Baidu 20170306
Bkav 20170306
CAT-QuickHeal 20170306
CMC 20170306
ClamAV 20170306
Comodo 20170306
Cyren 20170306
DrWeb 20170306
ESET-NOD32 20170306
F-Prot 20170306
Fortinet 20170306
Ikarus 20170306
Jiangmin 20170306
K7AntiVirus 20170306
K7GW 20170306
Kaspersky 20170306
Kingsoft 20170306
Malwarebytes 20170306
McAfee 20170306
Microsoft 20170306
NANO-Antivirus 20170306
Panda 20170306
Rising 20170306
SUPERAntiSpyware 20170306
Sophos 20170306
Symantec 20170306
Tencent 20170306
TrendMicro 20170306
TrendMicro-HouseCall 20170306
Trustlook 20170306
VBA32 20170306
VIPRE 20170306
ViRobot 20170306
Webroot 20170306
WhiteArmor 20170303
Yandex 20170225
Zillya 20170304
ZoneAlarm by Check Point 20170306
Zoner 20170306
nProtect 20170306


From 61 different AV resources there are 48 negatives (nothing found) and 13 'results'.

Now, first let me say this; I'm pretty sure my computer is 'clean', but nobody can ever be 100% sure, there are some pretty clever rootkits around, so I don't know that there is not malware on my computer somewhere. Take war2observe for example. It works by injecting  a piece of code into a "code-cave" in the wc2 exe..... it's a worm, just not a malicious one.

Nobody really knows for sure that any .exe .dll .ocx etc. on their computer is completely safe, if I send some file to VirusTotal and there's results, I have to consider them. You can never be completely sure.... EXCEPT for this one case. Where I have personally written the code, then compiled it, then (and this is important) immediately compressed it using the most aggressive executable compression available.... always the most exhaustive/slowest methods.

At this point it comes down to information/entropy vs. size. There are no 'code caves' left. There is no way to 'inject' a worm into it and have the program still perform its expected function without increasing the file size. That amount of bytes simply cannot hold the extra information, not without completely re-writing it in a different language (i.e pure ASM - this one is a bastardised C prog), and only a human can do that, not malware.

I use open source exe compression that I have altered so that it cannot be automatically unpacked by either malware OR anti-virus, because nobody else knows how I have altered it.... I won't go on about that part of it, but for now I'm what I'm saying that when I have just compiled and compressed a program from my own source code, is the only time that I can upload a file to be virus checked and I absolutely 100% KNOW it its safe. Nobody else knows this for sure, but I did it, so I know ... and yet we get "13 results" a few different results, but there's 6 out of the 13 all saying it is a "Trojan.Heur.emGfXPgbohm". OMG! It must be true!  ;D

But because I know it is false, I now know something else. These sources are all using the same AV engine (or at the very least the same virus definitions and a clone of the engine). Without a doubt. Of the 6 sources one stands out as being a genuine AV company. "BitDefender" are Romanian group, and a reasonably major player in the industry. So at this point I KNOW the other 5 are just re-branding BitDefender's engine. Never bothered looking before, but while writing this post, within 2 minutes of looking I came up with THIS (https://en.wikipedia.org/wiki/Multiscanning) page listing "Multiscanning" vendors. At the top of the page it lists 4 out of the 5 (Emsisoft,F-Secure,GData and eScan) as using the BitDefender engine. As for "Arcabit", whoever the hell they are, I couldn't be bothered but I'll lay money if you look them up, they're exactly the same.

So. Our 13 out of 61 "Results" have shrunk to 8 out of 54. Two of those are saying "malicious" and "confidence", my guess: they are nobodys with dodgy "everything turned up to 11" implementations of one of the open source projects.... I mean "CrowdStrike Falcon" BAHAHAHA, sorry but if that name turned up in the war2bne channel you'd take one look at it and say "noob"  ;D

Here's our real results:

BitDefender              Gen:Trojan.Heur.emGfXPgbohm
Invincea                   worm.win32.bartly.a
McAfee-GW-Edition    BehavesLike.Win32.Sality.lc
Qihoo-360                 HEUR/QVM18.1.0000.Malware.Gen
TheHacker                 Posible_Worm32
   and of course...
Avira                         TR/Crypt.ULPM.Gen

.... and these people say its safe:
AVG, Avast, Kaspersky, Kingsoft, McAfee (Std), Microsoft, Symantec, TrendMicro, ZoneAlarm  .... and 39 other AV providers.

Anyway, for starters you can see why I LMAO at noobies claiming "68% confidence"... lol I've actually started laughing again writing that, for real...  I mean some newbie newbie called CrowdStrikeFalcon!!! just turns up in the channel and claims that he is exactly "68% confident" that he knows more about the game than mikulz, styx, Day, Player, Medievh, Ouin... etc (sorry ppl i forgot)... ROTF...

Anyway, stuff such as: "BehavesLike.Win32.Sality.lc" is fair enough. IDK what "Sality" is, but its probably a naughty program that is written in C, calls "GetAsyncKeyState", "OpenProcess", and "ReadProcessMem", is compiled with WATCOM, and then compressed in a non-standard way. McAffee is a decent provider, in addition to their normal AV product they obviously have another product variant aimed at the customer who wants to see lots of results.... that's fine, they just said, "owns a tyre-iron" not "is a serial killer". Annoying, but not technically untrue (I assume).

That's the sort of thing they all should be putting. because the fact of the matter is these are all the result of the AV software saying 2 things:

(1) This program is protecting it self in ways I don't understand, so I cant mess with it how I want to... this makes me worry.
(and Lamb says,"yes that's right mother-lover, and neither can the worms when they try to find a home")

(2) When it unpacks itself I can see the functions its linking, and now I've got an excuse to make some alarmist rubbish up because I don't trust it and OMG ITS USING THE KEYBOARD!  et.al..... and besides: Warnings Generate Sales. ;)

"TheHacker", despite their rather dodgy sounding name, give a reasonable response possible worm. Not a claim, just a possibility, and the way that this program functions it could conceivably be a "worm" like Observer is. In this case it isn't but it does use some of the tools that a worm would need, so "possible worm"... sure, hf with that.

"Invincea", whoever they are, just say worm.win32.bartly.a, same thing, they really should put "possibly", or "behaves like"

"Qihoo-360" - HEUR/QVM18.1.0000.Malware.Gen
lol...WTH is a "Qihoo"? You just invented that crap on the spot, didn't you? heh

I guess, this means "general malware". Also note the "HEUR",  in this and the BitDefender response, which stands for heuristic.

"As opposed to signature-based scanning, which looks to match signatures found in files with that of a database of known malware, heuristic scanning uses rules and/or algorithms to look for commands which may indicate malicious intent." SOURCE (http://www.thefreedictionary.com/heuristic)

i.e. "Carries a tyre-iron" ;)


And then there's these 2...
BitDefender              Gen:Trojan.Heur.emGfXPgbohm
Avira                         TR/Crypt.ULPM.Gen

Sorry, but it looks to me like Avira also uses the the BitDefender engine as at least part of it's scanning process, because I'm finding it hard to believe that 2 separate engines got it that wrong. At least they have their own classification of the result, because of all the responses this one is the most incorrect. "Worm"... maybe. It's not a worm, but if you wanted to make stuff up, at least it's believable garbage,.... but "Trojan"... bzzzz.. FAIL. Sorry. No freakin' way.

The whole point of the Trojan horse (actually a Roman Horse lol) was to allow a few men to get into Troy and open the gates so the Roman army could storm in and sack the city. The one thing all software trojans do... in fact pretty much all malware these days, is access the network. That is the whole point, so they can download a bunch of other nasty stuff and install it, but this program has absolutely no code whatsoever that does anything at all with any network functions or services. So sorry BitDefender, but that is just a big fat FAIL.


I suppose if I un-protected the exe, so that the AV software could poke around a lot more, some of them might feel better about it, but for sure some of them would still come up with some lame warning. This is just a marketing technique.

But, if I did that, it would not only make the file bigger, it would also make it a lot less safe because then any malware that may be floating around in the future can also access, and possibly infect it... not to mention wannabe WC2 hackers who might possibly like to reverse engineer some of my stuff  :o

It's better if people can just be reassured that:

AVG, Avast, Kaspersky, Kingsoft, McAfee, Microsoft, Symantec, TrendMicro, ZoneAlarm  .... and 39 other Anti-Virus providers all say its fine.  :) HF

Title: Re: Nerd's Corner
Post by: 8)MikulZ(8 on March 06, 2017, 04:36:49 PM
Yeah I mainly posted because I thought some might think it's a virus + I actually wanted to know what is causing avira to think it's a virus, so thanks for the explanation  ^-^. And sorry for triggering you to write so much  :)  :(. It was a good read tho like all your posts here so... thanks lol
Title: Re: Nerd's Corner
Post by: Lambchops on March 06, 2017, 04:49:34 PM
d sorry for triggering you to write so much

LOL .... yeah I never normally do that ;D

....no worries mate, like I say, thanks for letting me know. :) AV software is a bit of a pet subject for me anyway, I'm surprised I havn't written about it before now.
Title: Re: Nerd's Corner
Post by: Lambchops on March 06, 2017, 05:53:04 PM
smurfs!!
[url]http://imagizer.imageshack.us/v2/516x387q90/923/Im3GD2.jpg[/url] ([url]http://imagizer.imageshack.us/v2/516x387q90/923/Im3GD2.jpg[/url])



(http://imagizer.imageshack.us/v2/516x387q90/923/Im3GD2.jpg)

smurfs having a blue life bar below the portrait is just freakn' awesome ;D

Title: Re: Nerd's Corner
Post by: mousEtopher on March 07, 2017, 09:39:51 AM
hooooooooly shit, Lamby, you made the big ss thing!

(https://media.tenor.co/images/3d702414b1acfed81bea00d3c076dcf8/raw)
Title: Re: Nerd's Corner
Post by: Lambchops on March 08, 2017, 10:52:17 AM
hooooooooly shit, Lamby, you made the big ss thing!

awww thx mousey. now I'm blushing :)
Title: Re: Nerd's Corner
Post by: Lambchops on March 08, 2017, 11:05:06 AM
 I updated the SS grabber (http://forum.war2.ru/index.php/topic,2703.msg50610.html#msg50610).

Now saves to PNG by default but will also save to JPG and/or bmp
also stamps the images with the PUD name, the time/date and the player names.

(http://ss.war2.ru/ss/9184.gif)

oops. just noticed the player names aren't the right colors. :( I'll fix that shortly.


updated link <3 mousey
Title: Re: Nerd's Corner
Post by: Incos on March 10, 2017, 06:35:59 AM
Ok lanky, I tried to use your PDF on ripping sprite sheets. However the grp converter has it skip frames. I use that sfqconvertor had the brood war icon. It only rips sheets that have the units all in a row.

Wardraft is outdated and for old war2.

Easy I also use your sheet editor, but when I group, am I grouping them allot just the animations that belong together like lambys tutorial?

And do you have the macro that sheets them with spaces and makes them war2 compliant available ?

I
Title: Re: Nerd's Corner
Post by: Lambchops on March 11, 2017, 05:55:59 AM
oops. just noticed the player names aren't the right colors. :( I'll fix that shortly.


Ok fixed that. Now writes player names in the correct color for the game.

(http://ss.war2.ru/ss/9186.gif) (http://forum.war2.ru/index.php?action=dlattach;topic=2703.0;attach=1119)

Also added -t switch to just take SS and exit if anyone wants to run it via the command line from another app.

Should be the final release for now.

Title: Re: Nerd's Corner
Post by: shesycompany on March 11, 2017, 09:07:41 AM
incos go to the easycompany thread..
Title: Re: Nerd's Corner
Post by: mousEtopher on March 11, 2017, 11:04:20 AM
I am a huge scrub and need help Lamby. I opened the app then went to single player custom scenario and pressed F6 key and it did the scrolling around thing & saved the file as .png but it's 0kb. halp

The original version that saves a bmp works though (after I figured out that having a 2nd monitor makes it do odd things... :D)
Title: Re: Nerd's Corner
Post by: mousEtopher on March 13, 2017, 10:00:36 AM
actually they're still coming out goofy without 2nd monitor (I thought it worked right at one point though)

(https://i.imgur.com/5TUfY2F.png)

I noticed crazy eights ss was buggy too http://forum.war2.ru/index.php?action=dlattach;topic=3047.0;attach=1132 (http://forum.war2.ru/index.php?action=dlattach;topic=3047.0;attach=1132)
Title: Re: Nerd's Corner
Post by: Lambchops on March 13, 2017, 01:03:03 PM
I am a huge scrub

won't hear of it   :-X

and need help Lamby.

OMG Sorry I missed this post and didn't reply mousey.

I opened the app then went to single player custom scenario and pressed F6 key and it did the scrolling around thing & saved the file as .png but it's 0kb. halp

The original version that saves a bmp works though (after I figured out that having a 2nd monitor makes it do odd things... :D)

Well firstly, cool I'm glad you got something working.

The first version just uses bread&butter file writing to save the internal buffer straight to a .BMP file. Very uncomplicated.

The next version uses the Windows GDI+ interface (GDIPlus.dll) to save to either PNG, JPG or BMP. This is done via the GdipSaveImageToFile func for all 3 image types, the format depends on the CLSID and encode paramaters you pass it.

It doesn't use anything that should interact with the screen or the desktop AFAIK, so in theory a dual monitor system should have no effect.

That being said, I don't have a dual monitor system to test it out on, and "in theory" has never stopped windows from messing things up before, however I would still check if there are any GDI+ updates of fixes released for your operating system.

Title: Re: Nerd's Corner
Post by: Lambchops on March 13, 2017, 02:44:53 PM
actually they're still coming out goofy without 2nd monitor (I thought it worked right at one point though)
I noticed crazy eights ss was buggy too

hmm. Ok thanks for letting me know.
This is unrelated to the  0 length .PNG problem.
(That is probably a bad class ID or encoders not installed properly type of thing)

Its good that you have text on the screen in your SS, from that I can see that the bitmap is being constructed and saved correctly.

The problem is that the screen offset is not being set correctly.
Could I ask what OS you are using and are you pressed for processor time... like VM or older comp? I should be able to get this fixed with a little bit of tinkering, but right now i have to be at court in 5 hours and I'd like to spend at least 1 of them asleep. bbl
 

Title: Re: Nerd's Corner
Post by: mousEtopher on March 13, 2017, 04:05:44 PM
np! thank you for your attention! c: I will test the png one on some other pcs to see if it works right and what I can learn. This pc is Win7 & plenty of available processor power

Good luck at court! fingers crossed for a sane, lamb-favoring outcome
Title: Re: Nerd's Corner
Post by: shesycompany on March 14, 2017, 12:15:37 AM
ive got the old one and it works in my win7..the bmp one.
Title: Re: Nerd's Corner
Post by: Lambchops on March 14, 2017, 05:30:09 AM
Ok. For the first problem, where the PNG file is 0 length, would you please run the attached .exe on any machine that has this problem then post the results.

the .exe will produce a small text file, which should look something like this:

Code: [Select]
Class ID   : {557cf400-1a04-11d3-9a73-0000f81ef32e}
Format ID  : {b96b3cab-0728-11d3-9d7b-0000f81ef32e}
Codec      : Built-in BMP Codec
Module     :
Description: BMP
File Types : *.BMP;*.DIB;*.RLE
MIME Type  : image/bmp

-------------------------------------------

Class ID   : {557cf401-1a04-11d3-9a73-0000f81ef32e}
Format ID  : {b96b3cae-0728-11d3-9d7b-0000f81ef32e}
Codec      : Built-in JPEG Codec
Module     :
Description: JPEG
File Types : *.JPG;*.JPEG;*.JPE;*.JFIF
MIME Type  : image/jpeg

-------------------------------------------

Class ID   : {557cf402-1a04-11d3-9a73-0000f81ef32e}
Format ID  : {b96b3cb0-0728-11d3-9d7b-0000f81ef32e}
Codec      : Built-in GIF Codec
Module     :
Description: GIF
File Types : *.GIF
MIME Type  : image/gif

-------------------------------------------

Class ID   : {557cf405-1a04-11d3-9a73-0000f81ef32e}
Format ID  : {b96b3cb1-0728-11d3-9d7b-0000f81ef32e}
Codec      : Built-in TIFF Codec
Module     :
Description: TIFF
File Types : *.TIF;*.TIFF
MIME Type  : image/tiff

-------------------------------------------

Class ID   : {557cf406-1a04-11d3-9a73-0000f81ef32e}
Format ID  : {b96b3caf-0728-11d3-9d7b-0000f81ef32e}
Codec      : Built-in PNG Codec
Module     :
Description: PNG
File Types : *.PNG
MIME Type  : image/png

Title: Re: Nerd's Corner
Post by: mousEtopher on March 14, 2017, 07:41:03 PM
Code: [Select]
Class ID   : {557cf400-1a04-11d3-9a73-0000f81ef32e}
Format ID  : {b96b3cab-0728-11d3-9d7b-0000f81ef32e}
Codec      : Built-in BMP Codec
Module     :
Description: BMP
File Types : *.BMP;*.DIB;*.RLE
MIME Type  : image/bmp

-------------------------------------------

Class ID   : {557cf401-1a04-11d3-9a73-0000f81ef32e}
Format ID  : {b96b3cae-0728-11d3-9d7b-0000f81ef32e}
Codec      : Built-in JPEG Codec
Module     :
Description: JPEG
File Types : *.JPG;*.JPEG;*.JPE;*.JFIF
MIME Type  : image/jpeg

-------------------------------------------

Class ID   : {557cf402-1a04-11d3-9a73-0000f81ef32e}
Format ID  : {b96b3cb0-0728-11d3-9d7b-0000f81ef32e}
Codec      : Built-in GIF Codec
Module     :
Description: GIF
File Types : *.GIF
MIME Type  : image/gif

-------------------------------------------

Class ID   : {557cf405-1a04-11d3-9a73-0000f81ef32e}
Format ID  : {b96b3cb1-0728-11d3-9d7b-0000f81ef32e}
Codec      : Built-in TIFF Codec
Module     :
Description: TIFF
File Types : *.TIF;*.TIFF
MIME Type  : image/tiff

-------------------------------------------

Class ID   : {557cf406-1a04-11d3-9a73-0000f81ef32e}
Format ID  : {b96b3caf-0728-11d3-9d7b-0000f81ef32e}
Codec      : Built-in PNG Codec
Module     :
Description: PNG
File Types : *.PNG
MIME Type  : image/png


Here it is. The other pc that's nearby does the exact same thing w/ both versions. I think they're both using the same version of Win7 installed from the same place, so it might be related to that? Don't worry about it if it's going to be a headache for you to troubleshoot, it's probably my own fault for having some inferior version of windows c:
Title: Re: Nerd's Corner
Post by: Lambchops on March 15, 2017, 06:37:35 AM
Great, thanks very much for doing that, and no don't be concerned that you are causing me problems, you are helping me. :) If I have written routines to do basic things like save an image, I need to know that they will work as they are supposed to, and if not, find out why, and fix the issue.

I really should have a bunch of VMs set up running different versions of windows so I can test things out to make sure that they are work in all environments, but at the moment I am limited to just my main machine, which remains, as it has been for many years, a 32 bit XP installation. So until told otherwise I can only assume that when things work on that that they will work everywhere else.

So just making sure I have this right: you have tried with 2 different systems, both running win7, both fail to save a .png image, and you have now ruled out your monitor/desktop configuration as a factor? Also using the original version that saves to .BMP you have, at lest some of the time, had glitchy SSs saved that are not constructed correctly on both systems?


Title: Re: Nerd's Corner
Post by: mousEtopher on March 15, 2017, 02:39:51 PM
Yes that's right. I went and pulled all the original .bmp screenshots I took from the trash and they're all bugged, so as far as I can tell the .bmp one bugs 100% of the time for me. It does that whether 2nd monitor is plugged or unplugged. (The other pc has a 2nd monitor too though actually, did not try it unplugged.) The newer version saves empty .pngs every time on both pcs. I also have another laptop laying around w/ I think a different version of windows (7 pro or home or something) which I can try if it will be useful for you. Also Nedro said he is having the same glitch with the .bmp version
Title: Re: Nerd's Corner
Post by: Lambchops on March 16, 2017, 03:58:38 AM
OK have updated it again HERE (http://forum.war2.ru/index.php?action=dlattach;topic=2703.0;attach=1146)

Hopefully it should work Ok on all systems now, hard to tell "flying blind" because it works here when I test it...

Should save to PNG but will check for correct GDI+ behavior and switch to BMP if there's a problem.

Have added a check to ensure that the screen offset is being set correctly, which should stop "glitchy" images being saved. If this is still happening I will just have to slow down the capture loop until it is stable. This will allow time for WC2 to have the screen updated. IDK why this is happening as in theory that function should not return until the screen has been updated - and that is how it works on my computer, but it's hard to guess how another version of Windows is behaving.

Another thing I thought could *MAYBE* be a problem is the cpusavior program, so I tried it with that running and on my system all it did was make the image capture take 10x as long - but it still worked properly, however if you are still having problems and you are using the "cpusavior" app please also test without that.

Please let me know how it goes.

Thanks for your help.  :)
Title: Re: Nerd's Corner
Post by: mousEtopher on March 16, 2017, 01:06:00 PM
it's glorious, ty lamby!!! Now when I take the ss I can see that it's scrolling across the minimap in neat rows left/right & top/bottom which it wasn't doing before. Saving as .bmp which is fine, 16MB of pure pudy goodness! :D thank you for your effort! c:

(https://i.imgur.com/7fdILHT.png)

(Beetle Island people, great chaotic map!)
Title: Re: Nerd's Corner
Post by: Lambchops on March 17, 2017, 06:17:02 AM
it's glorious, ty lamby!!!

Cool bananas  :D  ... and thank YOU for your testing and reports - that stuff is invaluable. Wish I knew why the GDI+ stuff isn't working though  :-\  oh well... another day.

What sort of image capture / save times is it reporting?

(Beetle Island people, great chaotic map!)

Yeah, fun map. I think we've done that one once or twice  :)
Title: Re: Nerd's Corner
Post by: Lambchops on March 17, 2017, 06:25:15 AM
   ... and damnit there's still a glitch at 3 o'clock  grrrrr.

I'm going to have to inject this thing aren't I? ..... at least the anti-virus software will finally be right calling it a worm  ;D

Title: Re: Nerd's Corner
Post by: mousEtopher on March 17, 2017, 10:57:23 AM
oh yeah, so there is, my attention to detail is so bad. :< Here are outputs from ant trails, nwtr, and river kwai:

(https://i.imgur.com/Wn0R5fA.png)

nwtr looks perfect to me but I might be overlooking again. Others have similar 3oclockish bugs https://i.imgur.com/cI58POt.png https://i.imgur.com/8gVm9S9.png
Title: Re: Nerd's Corner
Post by: Lambchops on March 20, 2017, 09:41:50 AM
Hey  :)
Sorry I've been MIA for a few days, thanks for posting that output.
Have made a self checking version (http://forum.war2.ru/index.php?action=dlattach;topic=2703.0;attach=1162).

It takes a SS then goes back through every screen in reverse order and gets it again, then checks if it's the same as the one from the first pass. If anything doesn't match it gets that screen again taking extra time/precautions and hopefully making sure that it has the right image. It's hard to tell because it just never fails on my machine.

Please try it out. It will also produce a small text file called "SSgrab.txt" that will look something like this:
Code: [Select]
Assuming single player mode.
Map Dimensions 128x128
Image aquired in 0.09 seconds
Check/re-aquire in 0.06 seconds
GdiplusStartup returned Ok
GdipGetImageEncodersSize returned Ok
GdipGetImageEncoders returned Ok
GdipCreateBitmapFromGdiDib returned Ok
GdipSaveImageToFile returned Ok
GdipDisposeImage returned Ok
GdiplusShutdown returned Ok

Checking GDI+ output
GDI+ confirmed OK

GDI+ check/Save (png) 0.36 sec
Complete. Total Time 0.52 seconds

Assuming single player mode.
Map Dimensions 128x128
Image aquired in 0.09 seconds
Check/re-aquire in 0.06 seconds
GdiplusStartup returned Ok
GdipCreateBitmapFromGdiDib returned Ok
GdipSaveImageToFile returned Ok
GdipDisposeImage returned Ok
GdiplusShutdown returned Ok
Save (png) 0.16 sec
Complete. Total Time 0.31 seconds

Which should help me track down why the PNG save is failing, if you can please post the results.



Title: Re: Nerd's Corner
Post by: Lambchops on March 20, 2017, 12:46:36 PM
RE-PURPOSING COMMON PORTS FOR WC2
Maybe some programmer should change the ports in the files from war2 : instead 6112-6119 make it on a port range which are usually open.
That could help a lot for all !!!

This is a nice idea, but I'm pretty sure it wouldn't work in most cases. There MAY be a solution here for some people, depending on their gear/connection, IMHO it's unlikely, but if you want to try....

The first thing I should point out is that you can already select your game port via the CE installer.

This is the only port you need to worry about (6112 by default).

The 6112-6119 thing is a misnomer which was probably introduced into some docs that were being written at the same time BNE was being written and before they had the final IPX --> UDP conversion sorted out. When you are in a game you may be getting WC2 game packets on a variety of ports, depending on whether any of the other players have changed their default port. THIS DOES NOT MATTER for hosting, it is all taken care of by hole punching. It's only that single game port that is the issue.


RELEVANT STUFF
1) “open” is an over-simplification. Ports are not “open” or “closed”.

2) Routing tables aren't made to assume that there is only one end user connected to them, even if that is all there is. The job they are doing is to try to find the right place to send each packet.

3) What we tend to refer to as “opening” a port is adding a rule to the routing table to tell it to send traffic on that port to a particular place (our WC2 computer).

4) If we can't do that then we need to give the router some kind of hint to let it know we want those packets.

5) Even for common ports, packets are not just forwarded without the router having more information, as per (2) above they still don't know where to send it. The only ports for which this is done are called “Multicast” ports.



MULTICAST:
In theory a router receiving a packet on a multicast port will re-transmit it to all nodes downstream. I'm sure you can all guess what these ports were used for 99% of the time – yes, either spam or hacking. As a result most servers do not re-transmit multicast traffic, they just ditch it without a second thought. So apart from all the other logistical issues there would be with using one of these ports, you can bet if your provider is not letting you add a simple routing rule for one port, there's no way they will be sending you multicast traffic.

SO, USING COMMON “OPEN” PORTS:
Let's use the example of a very common port that handles UDP traffic, port 53, which is the port for DNS. Anything accessing the network using domain names needs to use DNS to translate the name (i.e. server.war2.ru)  into an IP address (i.e. 145.233.94.234), which is what the network protocol actually uses.

So a router has 3 computers attached to it, with people using web-browsers. Every time one of the 3 users loads a page, the address of the page (i.e. Forum.war2.ru) will be looked up using a DNS, then the HTML for that page is loaded which might include another 10 embedded items, like images, youtube vids or whatever, that are all hosted on different sites, and the HTML has named addresses in it so an additional DNS lookup may be required for each one of these. But even if the 3 computers are all using the same DNS server, they will all get the correct responses to their queries returned to them (and only them).

How? Well for UDP traffic in general ( DNS is UDP ) the router just keeps track of which computer was the last one to send a packet OUT to a given address on a given port, then when any traffic arrives from that address on that port, it sends it back to that computer – this is where the “hole punching” thing comes in...... but for the case where our 3 users are all simultaneously loading pages with 10-20 DNS lookups each, things would still get messed up.

So, in addition to that, for commonly used ports that are reserved for known protocols  like 53, 80 ,443 etc. the LAN router, and/or the relevant local client service will often also be doing some amount of port translation. i.e. The to:/from: port numbers on the packets will be different. DNS servers are usually dedicated to just that single job and will accept requests on a broad range of ports, not just 53. They just check if any incoming traffic on any port is a valid DNS request, then if so, respond to it. So computer A will be talking to the DNS server on port 53:100 and computer B will be using 53:1987 or whatever. i.e. 'A' sends requests with “To Port: 100” and “From Port: 53” then the DNS server will respond with  “To Port: 53” and “From Port: 100” so the LAN router will send it back to the correct node, where it will end up on port 53 and go to the correct service (DNS).

So you can see that even for the most commonly used UDP service port: the DNS port #53, in some cases NONE of the external traffic will actually be on port 53, and regardless of that, when some random packet turns up from an unknown address on port 53, even if the local router accepts it as being valid DNS traffic, it still doesn't know if it should be sent to computer 'A', 'B' or 'C', and as I have said, the fact that there may be only one computer connected locally usually does not change this. If the router can't find a valid reason to send a packet to a node, it won't. That's its job.

TRY IF YOU WANT:
So if you want, you can try changing you game port to 21, 25, 53, 80, 123, or 443. Perhaps even 37, 43,  67, 68, 137, 143 or 8080, and just hope that there is some kind of exception built into the upstream routing.

However this approach also requires all other players in a game to be able to reliably send you WC2 data over these ports, and the chances of NOBODY having these ports either A) blocked, B) running on stateful or app-layer firewalls, or C) being controlled by protocol specific daemons, seem fairly remote.

BEST BET:
For the people who are having issues because they are using some kind of mobile service that reduces it's bandwidth by tracking its routing upstream of the end-user, I think your best bet for something that is might possibly “sneak through” and not get butchered by everyone else's firewalls might be one of these: 


    2195 - Apple Push Notification Service
    3689 - iTunes, AirPlay
    4488 - Apple WACS
    5223 - Apple Push Notification Service
    5228 - Google play store,  Android cloud messaging

As a wild stab-in-the-dark, I'd try 4488 first.

But this is just if you want to try and hope, I don't really think there is much chance of it working.

**and using an Apple port definitely wouldn't work through an Apple phone, or probably not even if there was an Apple phone connected anywhere on the network.**
Title: Re: Nerd's Corner
Post by: shesycompany on March 20, 2017, 03:50:02 PM
lamb your back! :-*
Title: Re: Nerd's Corner
Post by: Lambchops on March 21, 2017, 09:39:44 AM
lamb your back! :-*
Hehe :) ya I'm around, just stupid RL cramping my style a bit.
Title: Re: Nerd's Corner
Post by: mousEtopher on March 21, 2017, 01:03:04 PM
Hey  :)
Sorry I've been MIA for a few days, thanks for posting that output.
Have made a self checking version ([url]http://forum.war2.ru/index.php?action=dlattach;topic=2703.0;attach=1162[/url]).

It takes a SS then goes back through every screen in reverse order and gets it again, then checks if it's the same as the one from the first pass. If anything doesn't match it gets that screen again taking extra time/precautions and hopefully making sure that it has the right image. It's hard to tell because it just never fails on my machine.

Please try it out. It will also produce a small text file called "SSgrab.txt" that will look something like this:
Code: [Select]
Assuming single player mode.
Map Dimensions 128x128
Image aquired in 0.09 seconds
Check/re-aquire in 0.06 seconds
GdiplusStartup returned Ok
GdipGetImageEncodersSize returned Ok
GdipGetImageEncoders returned Ok
GdipCreateBitmapFromGdiDib returned Ok
GdipSaveImageToFile returned Ok
GdipDisposeImage returned Ok
GdiplusShutdown returned Ok

Checking GDI+ output
GDI+ confirmed OK

GDI+ check/Save (png) 0.36 sec
Complete. Total Time 0.52 seconds

Assuming single player mode.
Map Dimensions 128x128
Image aquired in 0.09 seconds
Check/re-aquire in 0.06 seconds
GdiplusStartup returned Ok
GdipCreateBitmapFromGdiDib returned Ok
GdipSaveImageToFile returned Ok
GdipDisposeImage returned Ok
GdiplusShutdown returned Ok
Save (png) 0.16 sec
Complete. Total Time 0.31 seconds

Which should help me track down why the PNG save is failing, if you can please post the results.


ok done! I think it's perfect this time? *tentatively hopeful*

(https://i.imgur.com/9TfuxbQ.png)

here is the grab:

Code: [Select]
Assuming single player mode.
Map Dimensions 128x128
Image aquired in 0.87 seconds
Screen check fail (114,114)... reaquiring
Check/re-aquire in 1.25 seconds
GdiplusStartup returned Ok
GdipGetImageEncodersSize returned Ok
GdipGetImageEncoders returned Ok
GdipCreateBitmapFromGdiDib returned Ok
GdipSaveImageToFile returned InvalidParameter
GdipDisposeImage returned Ok
GdiplusShutdown returned Ok

Checking GDI+ output
GDI+ Error - reverting to BMP output.

bitmap saved to SS_Cliffhanger BNE - 20170321-125412.bmp
GDI+ check/Save (png) 0.23 sec
Complete. Total Time 2.37 seconds

Assuming single player mode.
Map Dimensions 128x128
Image aquired in 0.81 seconds
Screen check fail (14,14)... reaquiring
Check/re-aquire in 1.22 seconds
bitmap saved to SS_Cliffhanger BNE - 20170321-125524.bmp
Save (png) 0.00 sec
Complete. Total Time 2.04 seconds

Title: Re: Nerd's Corner
Post by: Lambchops on March 21, 2017, 05:08:46 PM
ok done! I think it's perfect this time? *tentatively hopeful*

Yay! :) Thanks so much for all your help. You're awesome  :fro:

Yes, at least it's ending up with a correct image. I'm glad the re-checking thing worked cos I've got no way of testing it at the moment. One of these days I'll get my Win7 machine set up again and check it all out.

and now I know where to start looking with the GDI+ thing -->

       "GdipSaveImageToFile returned InvalidParameter"

Hardly the world's most helpful error code, pretty much means "I didn't like one of the numbers", but it's a start. If it would fail on my computer it'd be easy to fix, but no such luck lol.


Title: Re: Nerd's Corner
Post by: Lambchops on March 23, 2017, 02:59:41 AM
"GdipSaveImageToFile returned InvalidParameter"

Oh, BTW:

Given this error, there's a fair chance that the JPG save might work, even if the PNG doesn't.

If you want to try, just put the attached .BAT file in the same folder as WC2FullSSc.exe and double click on it.

Title: Re: Nerd's Corner
Post by: mousEtopher on March 23, 2017, 08:41:07 AM
that works great, ty! c:
Title: Re: Nerd's Corner
Post by: Lambchops on March 23, 2017, 02:33:25 PM
that works great, ty! c:

NP :)



... and for those who are into such things, I've just done a big update to my

                Palette Editor (v1.0.2).


--> CHECK IT OUT. (http://forum.war2.ru/index.php?action=dlattach;topic=2703.0;attach=1176) <--


Title: Re: Nerd's Corner
Post by: shesycompany on April 02, 2017, 10:37:17 AM
thought of a good use for this ..if u got a good printer..a war2 map art gallery in your house :P

excellent work lamb!
Title: Re: Nerd's Corner
Post by: Incos on April 03, 2017, 10:29:59 PM




... and for those who are into such things, I've just done a big update to my

                Palette Editor (v1.0.2).

Nice edit to the tutorial. It's almost a sprite editors  if you could load up a bmp with say 60 frames or scroll on it. Really good


--> CHECK IT OUT. (http://forum.war2.ru/index.php?action=dlattach;topic=2703.0;attach=1176) <--



[/quote]
Title: Re: Nerd's Corner
Post by: Lambchops on April 06, 2017, 04:39:56 AM
Nice edit to the tutorial. It's almost a sprite editors  if you could load up a bmp with say 60 frames or scroll on it. Really good

Yeah I'd like to do a GRP editor, but that will have to wait for now. Living in my car - nowhere to plug in my computer.... :(

Title: Re: Nerd's Corner
Post by: shesycompany on April 06, 2017, 01:05:21 PM
 :'(  dam wish i could help lamb.
Title: Re: Nerd's Corner
Post by: shesycompany on April 29, 2017, 09:43:57 PM
tupac put lamb stuff somewhere^ there as lamb stuff etc
Title: Re: Nerd's Corner
Post by: Lambchops on January 30, 2018, 02:36:46 AM
PUD File Format Stuff


Quote from: easycompany on 2017-02-26, 03:50:18

    hex(h)
    80 (00) value =01 bnet 00= custom map<--- very important this is


Ok. Not really sure, but I'm assuming the "80" at the start of this line is a file offset, i.e. the position in the PUD file where this value should be set ya??

Not sure, but i should give a quick description of how PUD files are formatted - perhaps you already know this IDK.

PUD FILE FORMAT

The PUD file format is like a simplified RIFF format (which, incidentally is what an AVI file is). It consists of sections. each section is formatted like this:

Code: [Select]

DWORD        4CC
DWORD        Size
(Size bytes)  Data


A '4CC' is a "four character code". It's just used like a name for the section, but it always contains exactly 4 characters ('DIVX' is a 4CC). 4CCs are kind of cool because they are easily readable by a human, and usually kind of describe what they denote, but also because they are exactly 4 bytes, and 4 bytes is a DWORD (32bit value) they can be handled by the processor as a single number and don't need to be processed as a string.... anyway, its a name that has 4 characters (letters).

i.e. the section that contains the starting gold for each player is called 'SGLD', and the section that contains the list of all the units on the map is called 'UNIT', while the section that contains the unit data (specs for each unit type... HP damage etc.) is called 'UDTA'

Most of the sections appear in all PUDs, some don't. i.e. the restriction section that allows a player to train certian units/upgrades but not others is called 'ALOW'. A 'normal' PUD that does not have any restrictions (you can have all the unit types) does not have an 'ALOW' section at all, however if this section is present WC2 will look at it and only allow the specified units/upgrades as per this section.

If you run my GrimEdit editor, and select Edit->Clipboard from the menu, you will see a list of common PUD sections. You can select the 4CC for each and it will display a (very) short description of what it is. You can then go to Modules->Player Properties, select a player, click one of the the "Units Allowed" etc. buttons and deselect a few things then click [Ok]. If you then go back to the "clipboard" you will see that an 'ALOW' section has been created and added to the PUD.

Many of the common sections that can appear towards the start of a PUD have a fixed length (i.e. 'SGLD' is always 32 bytes) which can make it appear that certain values occur at certain file offsets, because the sections are commonly written in the same order, however this is an illusion as the sections can be written in a different order or entirely new sections inserted into a PUD. ( this is how it is possible to create a file that is both a playable .PUD file and an executable .EXE file).

Also there are certianly sections whose length will vary from PUD to PUD... i.e. the size of 'UNIT' will depend on how many units are placed on the map.

It is by changing the sections that a PUD file is edited. If you look at the map description module in the ASM source you will see it loads/saves the 'DESC' section, while the Starting Resources module edits 'SGLD', 'SLBR' and 'SOIL'. There are (or used to be) descriptions of the common PUD sections floating around on the web.




                                      == :critter:== :peon:== :critter:== :peon:== :critter:== :peon:== :critter:==



Oh Hey, here ya go, found the section definitions. I downloaded this from somewhere in like 2002 or something   :D

PUD Format (Download) (http://forum.war2.ru/index.php?action=dlattach;topic=2852.0;attach=1069)


So your offset 0x80 is the very start of the data for the 'UDTA' section.
You can see it here - random cusom PUD is Mini BGH (SS of my trusty Hex Editor - I wrote that golden oldie in '97 - been using it ever since  :P).

(http://ss.war2.ru/ss/9156.gif)

So the red box shows the section 4CC 'UDTA' the blue box contains the dword length of the data for that section - in this case 0x1640 bytes (5696 in ape numbers), and following that inthe green box is the value you are setting, which is actually a 2-byte 'WORD' value, but as it is either 0 or 1, the high byte (which comes second) is always 0, so only the first byte is modified.

As you can see from the included file:

------------------------------------------------------------
6: Section 'UDTA', Unit Data

        word            use default data (0 no, 1 yes)
        110 words       overlap frames
        508 words       obselete data (ignore it) was .....
-------------------------------------------------------------

... it's that first WORD value "use default data"

and just to illustrate the issue with using file offsets for this type of file, here's the same information from an earlier description of PUD internals, which is entitled "PUD Maximum File Format"
-------------------------------------------------------------------------
00:006A-00:006B   W Era number
        0=Forest,1=Icelands,2=Wastelands,3=Swamps
        *4-255=forest
00:006C-00:006F   $ Header description "ERAX"
00:0070-00:0073   L Expansion era data length ( 2 B)
00:0074-00:0075   W Expansion Era number
        0=Forest,1=Icelands,2=Wastelands,3=Swamps
        *4-255=forest
00:0076-00:0079   $ Header description "DIM "
00:007A-00:007D   L Dimensions data length ( 4 B)
00:007E-00:0081   W Map X and Y dimensions (0 ?? .. 128max)
        *Map is always loaded only by Y size
        *i.e. Y*Y map size
00:0082-00:0085   $ Header description "UDTA"
00:0086-00:0089   L Unit data length ( 5950 B )
00:008A-00:008B   W Set if Should be used default data
        0=no,1=yes

00:008C-00:0167   W Overlap frames for each unit (0..109)
        * group to belong number
        * see "UNIT" section for units order
00:0168-00:0265   W Obsolete General grafix frames
-------------------------------------------------------------------

However as you can see here the value is denoted as being at offset 0x8A because the PUD file being described also contains the optional 'ERAX' section.

The only thing that can be guaranteed is that it is the first WORD in the data for the 'UDTA' section.


The data lengths in each section header construct the file i.e. as the 'UDTA' section in the Mini BGH PUD here is 0x1640 bytes long and starts at 0x80 then the next section header will be at 0x1640 + 0x0080 = 0x16C0, and indeed if you go to offset 0x16C0 in this PUD you will find 'UGRD' the "Upgrades" section 4CC followed by the DWORD 0x0000030E because the data for this section is 0x30E bytes long...
Title: Re: Nerd's Corner
Post by: Szwagier on February 02, 2018, 03:31:54 PM
If u want make map with "blizzard icon" you need add at end"..SIGN......"
If u want make map with "ladder icon" you need replace  TYPE...WAR2 MAP..˙",ć "VER ....DESC ...   into "D˝’Ş" 
Title: Re: Nerd's Corner
Post by: Lambchops on February 08, 2018, 12:30:46 PM
If u want make map with "blizzard icon" you need add at end"..SIGN......"
If u want make map with "ladder icon" you need replace  TYPE...WAR2 MAP..˙",ć "VER ....DESC ...   into "D˝’Ş" 


Ok cool. Thanks for the info @Szwagier 

Im actually playing with making a new map editor at the moment. IDK if I'll end up having time to finish it, but it's an interesting project.


(http://forum.war2.ru/index.php?action=dlattach;topic=2703.0;attach=2090)
Title: Re: Nerd's Corner
Post by: Delete mine too on February 08, 2018, 05:02:25 PM
If u want make map with "blizzard icon" you need add at end"..SIGN......"
If u want make map with "ladder icon" you need replace  TYPE...WAR2 MAP..˙",ć "VER ....DESC ...   into "D˝’Ş" 


Ok cool. Thanks for the info @Szwagier 

Im actually playing with making a new map editor at the moment. IDK if I'll end up having time to finish it, but it's an interesting project.


([url]http://forum.war2.ru/index.php?action=dlattach;topic=2703.0;attach=2090[/url])



It's so beautiful!! 😢😢
Title: Re: Nerd's Corner
Post by: Lambchops on February 09, 2018, 05:12:47 AM
It's so beautiful!! 😢😢


Yeah it's pretty. Doesn't do very much yet though but I think I've got the bulk of the tricky bits out of the way.

Got the other 3 tilesets and unit colors working yesterday :)  It's interesting to watch a particular view switch from forest to winter to swamp and compare... never noticed before but AFAIK there's actually no existing way to do this.


(http://forum.war2.ru/index.php?action=dlattach;topic=2703.0;attach=2092)
Title: Re: Nerd's Corner
Post by: shesycompany on February 09, 2018, 08:35:04 AM
 :o :o :o :o  :o  :o  :o  awesome .....how about a "tile part" in the pud a little mem editor can load peoples custom tiles???
Title: Re: Nerd's Corner
Post by: Lambchops on February 09, 2018, 09:18:20 AM
:o :o :o :o  :o  :o  :o  awesome .....how about a "tile part" in the pud a little mem editor can load peoples custom tiles???

There are no graphics in PUD files, that's all in EXE or MPQ.
Title: Re: Nerd's Corner
Post by: Szwagier on February 09, 2018, 09:24:18 AM
i can replace old titles
http://warcraft2.kalais.net/download.html (http://warcraft2.kalais.net/download.html)
Title: Re: Nerd's Corner
Post by: Delete mine too on February 09, 2018, 11:05:26 AM
It's so beautiful!! 😢😢


Yeah it's pretty. Doesn't do very much yet though but I think I've got the bulk of the tricky bits out of the way.

Got the other 3 tilesets and unit colors working yesterday :)  It's interesting to watch a particular view switch from forest to winter to swamp and compare... never noticed before but AFAIK there's actually no existing way to do this.


([url]http://forum.war2.ru/index.php?action=dlattach;topic=2703.0;attach=2092[/url])

What amazes me the most is how you can read the .pud and display the tiles correctly, units, and buildings. I can do unit data, stats, etc... just nothing with graphics....  I think you should add your offset editor to this map editor for more power ofcourse!! :) good job man keep it comming!
Title: Re: Nerd's Corner
Post by: Lambchops on February 10, 2018, 06:56:40 AM
What amazes me the most is how you can read the .pud and display the tiles correctly, units, and buildings. I can do unit data, stats, etc... just nothing with graphics....  I think you should add your offset editor to this map editor for more power ofcourse!! :) good job man keep it comming!

well for background graphics I just cheated (of course ;)) and did this:

- wrote a program to go throught every map I have (all of them) and make a list of every tile value used
  ( I only found 515 and im pretty sure a lot of those were from test PUDs I have made)

- wrote those 515 tile values to a PUD then loaded it in SP mode, did "on screen" and used my full SS
  grabber to snap a BMP of them.

- wrote a prog to extract each 32x32 section of the SS then index them to the list of 515 tile values,
  ensuring that each tile was only saved once, and multiple tile values that ended up with the same
  graphics just produced multiple indexes to the same tile.

- repeated for forest, winter, wasteland, swamp then put 4x (the list, the index, the graphics) and some
  procs to access/display them in a dll and linked it to the editor.

This way I can just pass it an MTXM value and it will supply the graphics. :fro: It was actually pretty simple to impliment once I worked out the method.

The unit graphics is just displaying GRPs, which I have documented and written routines for already, so no big deal. There's GRP stuff I probably won't bother implimenting, like the different critter graphics or the swampy buildings, because they're not really very relevant to map making.




Title: Re: Nerd's Corner
Post by: Szwagier on February 13, 2018, 05:00:44 PM
ok i tried discover where is mission objective
when i copied first mission from DP  xhum01 and saved as xhum02 i could kill alleria and turyalon, i couldnt kill danath
if i copied first mission human1 from TD and saved as xhum01 i got lose after 5 sec. SO mission objective are not in map
but
when i moved first mission human1 and played in scenario i wont win when i kill enemy units i will win when i made 4 farms and 1 rax so this is in map 
Title: Re: Nerd's Corner
Post by: Delete mine too on February 13, 2018, 06:28:32 PM
ok i tried discover where is mission objective
when i copied first mission from DP  xhum01 and saved as xhum02 i could kill alleria and turyalon, i couldnt kill danath
if i copied first mission human1 from TD and saved as xhum01 i got lose after 5 sec. SO mission objective are not in map
but
when i moved first mission human1 and played in scenario i wont win when i kill enemy units i will win when i made 4 farms and 1 rax so this is in map 
It's hardcoded in the exe I made a thread about this over a year ago. For people to have different missions or objectives they would need to run a program or everyone downloads a patched war2.exe...
Title: Re: Nerd's Corner
Post by: Szwagier on February 14, 2018, 01:55:19 AM
ok i tried discover where is mission objective
when i copied first mission from DP  xhum01 and saved as xhum02 i could kill alleria and turyalon, i couldnt kill danath
if i copied first mission human1 from TD and saved as xhum01 i got lose after 5 sec. SO mission objective are not in map
but
when i moved first mission human1 and played in scenario i wont win when i kill enemy units i will win when i made 4 farms and 1 rax so this is in map 
It's hardcoded in the exe I made a thread about this over a year ago. For people to have different missions or objectives they would need to run a program or everyone downloads a patched war2.exe...

Yes i remember but question is why mission 1 is working in scenario also
Title: Re: Nerd's Corner
Post by: shesycompany on February 14, 2018, 05:48:05 AM
it would be great if we could find them....destroy the dark portal ends game, would make it for a fun custom.
Title: Re: Nerd's Corner
Post by: Lambchops on February 14, 2018, 06:37:19 AM
when i moved first mission human1 and played in scenario i wont win when i kill enemy units i will win when i made 4 farms and 1 rax so this is in map

Interesting.

How are you playing it "in scenario"? You are converting it to a .PUD file? or a game save? ...or?
Title: Re: Nerd's Corner
Post by: Szwagier on February 14, 2018, 07:15:10 AM
All Maps from camping are Saved as pus

Pud file as normalnie map Saved human01. Pud like gardenofwar. Pud


OK now i know what happen i made farm rescue(passive) , if i wont acctive it, it means its opponent, if I destroy it with range (archers,cata etc) without touch it i will win


http://forum.war2.ru/index.php/topic,1956.0.html (http://forum.war2.ru/index.php/topic,1956.0.html)

It is possible to change? for example make 6 farms not 4?
anyway i tried with cheat enigne and i could change only res
Title: Re: Nerd's Corner
Post by: shesycompany on February 14, 2018, 04:40:20 PM
im sure it is,ill try also
Title: Re: Nerd's Corner
Post by: Szwagier on February 14, 2018, 04:56:22 PM
if it will work make also  tutorial how to do it ^^ I know only that if u need go to circle of power you can do it with every units(footman knight etc even if there is mission objective  is  archer)
Title: Re: Nerd's Corner
Post by: Delete mine too on February 14, 2018, 06:22:04 PM
All Maps from camping are Saved as pus

Pud file as normalnie map Saved human01. Pud like gardenofwar. Pud


OK now i know what happen i made farm rescue(passive) , if i wont acctive it, it means its opponent, if I destroy it with range (archers,cata etc) without touch it i will win


[url]http://forum.war2.ru/index.php/topic,1956.0.html[/url] ([url]http://forum.war2.ru/index.php/topic,1956.0.html[/url])

It is possible to change? for example make 6 farms not 4?
anyway i tried with cheat enigne and i could change only res

Yes, you could do that but I think it would be a pain IN the ass to locate that offset. Look for a map that has more objectives in common, like build 1 shipyard, etc... the more you can change the better you can search.
Title: Re: Nerd's Corner
Post by: shesycompany on February 14, 2018, 10:29:20 PM
oh well i mis read ..i thought you was talking about farm food value
Title: Re: Nerd's Corner
Post by: Lambchops on February 15, 2018, 02:03:57 AM

It is possible to change? for example make 6 farms not 4?
anyway i tried with cheat enigne and i could change only res
Yes, you could do that but I think it would be a pain IN the ass to locate that offset. Look for a map that has more objectives in common, like build 1 shipyard, etc... the more you can change the better you can search.

As an exe mod, yes. I dont think this is part of  the PUD file though, althought perhaps there is a single value somewhere in the PUD that designates one of the pre-defined sets of victory conditions. I don't think so, but that would be nice.
Title: Re: Nerd's Corner
Post by: Szwagier on February 15, 2018, 02:33:41 AM
Yes its in exe, but how do that cause u need Save exe with New value, i tired to do it but w2 didnt turn on
Title: Re: Nerd's Corner
Post by: Lambchops on February 15, 2018, 10:36:55 AM
Yes its in exe, but how do that cause u need Save exe with New value, i tired to do it but w2 didnt turn on

Ahh. Well it depends.

You can mod the process once the exe has been loaded.... or you can mod the exe file... BUT you can only mod the exe file if the value is in an initialized section. Virtual sections (uninitialised data) do not exist in the exe file so can only be modded in memory.

The offests in the exe file can be calculated from the values in the PE header. i.e. mem address - (ImageBase+VirtualAddress) + PointerToRawData = file address (IIRC something like that lol).

ImageBase is in the IMAGE_OPTIONAL_HEADER, and PointerToRawData, VirtualAddress are in the IMAGE_SECTION_HEADER for the relevant section. You will have to check the Characteristics to make sure the section isn't flagged as UNINITIALIZED.

Title: Re: Nerd's Corner
Post by: Lambchops on February 15, 2018, 10:58:54 PM
00 00 00 00 00 00 00 00 90 24 44 00 F0 25 44 00 00 00 00 00 A0 26 44 00 D0 28 44 00 80 29 44 00 E0 29 44 00 90 2A 44 00 20 2B 44 00 E0 2B 44 00 60 2C 44 00 F0 2C 44 00 80 2D 44 00 90 2E 44 00 C0 32 44 00 30 33 44 00 E0 33 44 00 80 34 44 00  u see them mem address the exe tells you swithc them up

well for example the first one 0x00442490
its an address in the .text section = code (instructions)

heres a dump of the WC2 PE header info:

Spoiler
Code: [Select]
Warcraft II BNE.exe - PE Image Information                              Lambchops  2002-2017

----------------------------------------


IMAGE_DOS_HEADER - SIZE: 62
  e_magic                          0x5A4D
  e_cblp                           0x0090
  e_cp                             0x0003
  e_crlc                           0x0000
  e_cparhdr                        0x0004
  e_minalloc                       0x0000
  e_maxalloc                       0xFFFF
  e_ss                             0x0000
  e_sp                             0x00B8
  e_csum                           0x0000
  e_ip                             0x0000
  e_cs                             0x0000
  e_lfarlc                         0x0040
  e_ovno                           0x0000
  e_res_1                          0x0000
  e_res_2                          0x0000
  e_res_3                          0x0000
  e_res_4                          0x0000
  e_oemid                          0x0000
  e_oeminfo                        0x0000
  e_res2_1                         0x0000
  e_res2_2                         0x0000
  e_res2_3                         0x0000
  e_res2_4                         0x0000
  e_res2_5                         0x0000
  e_res2_6                         0x0000
  e_res2_7                         0x0000
  e_res2_8                         0x0000
  e_res2_9                         0x0000
  e_res2_A                         0x0000
  e_lfanew                         0x00E8

----------------------------------------


IMAGE_SIGNATURE - SIZE: 4
  Signature                        0x00004550

----------------------------------------


IMAGE_FILE_HEADER - SIZE: 20
  Machine                          0x014C
  NumberOfSections                 0x0004
  TimeDateStamp                    0x3B01973F
  PointerToSymbolTable             0x00000000
  NumberOfSymbols                  0x00000000
  SizeOfOptionalHeader             0x00E0
  Characteristics                  0x010F

----------------------------------------


IMAGE_OPTIONAL_HEADER - SIZE: 96
  Magic                            0x010B
  MajorLinkerVersion               0x06
  MinorLinkerVersion               0x00
  SizeOfCode                       0x0008F000
  SizeOfInitializedData            0x0004B000
  SizeOfUninitializedData          0x00000000
  AddressOfEntryPoint              0x0007DC88
  BaseOfCode                       0x00001000
  BaseOfData                       0x00090000
  ImageBase                        0x00400000
  SectionAlignment                 0x00001000
  FileAlignment                    0x00001000
  MajorOperatingSystemVersion      0x0004
  MinorOperatingSystemVersion      0x0000
  MajorImageVersion                0x0000
  MinorImageVersion                0x0000
  MajorSubsystemVersion            0x0004
  MinorSubsystemVersion            0x0000
  Reserved1                        0x00000000
  SizeOfImage                      0x000DB000
  SizeOfHeaders                    0x00001000
  CheckSum                         0x00000000
  Subsystem                        0x0002
  DllCharacteristics               0x0000
  SizeOfStackReserve               0x00100000
  SizeOfStackCommit                0x00001000
  SizeOfHeapReserve                0x00100000
  SizeOfHeapCommit                 0x00001000
  LoaderFlags                      0x00000000
  NumberOfRvaAndSizes              0x00000010

----------------------------------------



IDD# 2  [ IMPORT ]
IMAGE_DATA_DIRECTORY - SIZE: 8
  VirtualAddress                   0x0009208C
  Size                             0x000000B4

IDD# 3  [ RESOURCE ]
IMAGE_DATA_DIRECTORY - SIZE: 8
  VirtualAddress                   0x000D9000
  Size                             0x00001210

IDD# 13  [ IMPORT ADDRESS ]
IMAGE_DATA_DIRECTORY - SIZE: 8
  VirtualAddress                   0x00090000
  Size                             0x000004E8

----------------------------------------


IMAGE_SECTION_HEADER - SIZE: 40
  Name                             .text
  VirtualSize                      0x0008E2EE
  VirtualAddress                   0x00001000
  SizeOfRawData                    0x0008F000
  PointerToRawData                 0x00001000
  PointerToRelocations             0x00000000
  PointerToLinenumbers             0x00000000
  NumberOfRelocations              0x0000
  NumberOfLinenumbers              0x0000
  Characteristics                  0x60000020
  - CNT_CODE
  - MEM_EXECUTE
  - MEM_READ

----------------------------------------


IMAGE_SECTION_HEADER - SIZE: 40
  Name                             .rdata
  VirtualSize                      0x00003420
  VirtualAddress                   0x00090000
  SizeOfRawData                    0x00004000
  PointerToRawData                 0x00090000
  PointerToRelocations             0x00000000
  PointerToLinenumbers             0x00000000
  NumberOfRelocations              0x0000
  NumberOfLinenumbers              0x0000
  Characteristics                  0x40000040
  - CNT_INITIALIZED_DATA
  - MEM_READ

----------------------------------------


IMAGE_SECTION_HEADER - SIZE: 40
  Name                             .data
  VirtualSize                      0x000445B0
  VirtualAddress                   0x00094000
  SizeOfRawData                    0x00018000
  PointerToRawData                 0x00094000
  PointerToRelocations             0x00000000
  PointerToLinenumbers             0x00000000
  NumberOfRelocations              0x0000
  NumberOfLinenumbers              0x0000
  Characteristics                  0xC0000040
  - CNT_INITIALIZED_DATA
  - MEM_READ
  - MEM_WRITE

----------------------------------------


IMAGE_SECTION_HEADER - SIZE: 40
  Name                             .rsrc
  VirtualSize                      0x00001210
  VirtualAddress                   0x000D9000
  SizeOfRawData                    0x00002000
  PointerToRawData                 0x000AC000
  PointerToRelocations             0x00000000
  PointerToLinenumbers             0x00000000
  NumberOfRelocations              0x0000
  NumberOfLinenumbers              0x0000
  Characteristics                  0x40000040
  - CNT_INITIALIZED_DATA
  - MEM_READ

----------------------------------------


IMAGE_IMPORT_DESCRIPTOR - SIZE: 20
  Characteristics                  0x0009235C
  TimeDateStamp                    0x00000000
  ForwarderChain                   0x00000000
  Name                             0x00092628
  FirstThunk                       0x0009021C

----------------------------------------

Imported from Storm.dll
  Hint  Function
-----------------------
  Ord0077
  Ord006D
  Ord0082
  Ord0073
  Ord008A
  Ord006A
  Ord0075
  Ord0078
  Ord007B
  Ord0066
  Ord007A
  Ord0079
  Ord0080
  Ord007F
  Ord01CE
  Ord01EB
  Ord0086
  Ord01F6
  Ord0193
  Ord01FC
  Ord0070
  Ord006B
  Ord0182
  Ord0185
  Ord0189
  Ord0186
  Ord0181
  Ord017F
  Ord013A
  Ord008B
  Ord01A9
  Ord00CE
  Ord00D3
  Ord00D8
  Ord01AF
  Ord00DD
  Ord01B2
  Ord01BD
  Ord007D
  Ord0071
  Ord00DE
  Ord0165
  Ord015A
  Ord00D0
  Ord0143
  Ord0145
  Ord010D
  Ord0109
  Ord01CF
  Ord0112
  Ord0117
  Ord01A5
  Ord01A8
  Ord01AC
  Ord01EE
  Ord0110
  Ord01D1
  Ord010B
  Ord0108
  Ord0113
  Ord0114
  Ord008C
  Ord0100
  Ord023B
  Ord00FF
  Ord0102
  Ord0164
  Ord0139
  Ord0162
  Ord015E
  Ord01AA
  Ord015F
  Ord01D4
  Ord0191
  Ord01F5
  Ord01FA
  Ord01F7
  Ord01FD
  Ord023C
  Ord0072
  Ord00FC
  Ord010A
  Ord00FD
  Ord010C
  Ord01A6
  Ord0089
  Ord01CA
  Ord01C9
  Ord01C6
  Ord01A7
  Ord0101
  Ord0105
  Ord01C5
  Ord0104
  Ord01C3

----------------------------------------



----------------------------------------


IMAGE_IMPORT_DESCRIPTOR - SIZE: 20
  Characteristics                  0x00092198
  TimeDateStamp                    0x00000000
  ForwarderChain                   0x00000000
  Name                             0x00092D96
  FirstThunk                       0x00090058

----------------------------------------

Imported from KERNEL32.dll
  Hint  Function
-----------------------
  0109: GetCurrentProcess
  0298: SetHandleCount
  0168: GetStdHandle
  01E5: LocalAlloc
  018E: GetVersion
  0230: RaiseException
  0125: GetFileSize
  00DE: GetComputerNameA
  0030: CreateDirectoryA
  0293: SetFileAttributesA
  028D: SetEnvironmentVariableA
  0025: CompareStringW
  0024: CompareStringA
  028C: SetEndOfFile
  00B9: FlushFileBuffers
  02A8: SetStdHandle
  02EE: VirtualAlloc
  0295: SetFilePointer
  016C: GetStringTypeW
  0169: GetStringTypeA
  02F1: VirtualFree
  01B6: HeapCreate
  01B8: HeapDestroy
  018F: GetVersionExA
  011C: GetEnvironmentVariableA
  0128: GetFileType
  011B: GetEnvironmentStringsW
  0119: GetEnvironmentStrings
  00C2: FreeEnvironmentStringsW
  00C1: FreeEnvironmentStringsA
  0257: RtlUnwind
  01BE: HeapSize
  01BD: HeapReAlloc
  0146: GetOEMCP
  00C9: GetACP
  00CF: GetCPInfo
  02CB: TerminateProcess
  01B4: HeapAlloc
  02DB: UnhandledExceptionFilter
  02D2: TlsGetValue
  029C: SetLastError
  02D0: TlsAlloc
  01BA: HeapFree
  01DD: LCMapStringW
  01DC: LCMapStringA
  0202: MultiByteToWideChar
  0301: WideCharToMultiByte
  008C: ExitProcess
  01CB: InterlockedIncrement
  0166: GetStartupInfoA
  008D: ExitThread
  02D3: TlsSetValue
  010C: GetCurrentThreadId
  004D: CreateThread
  026C: SetConsoleCtrlHandler
  012F: GetLocalTime
  0186: GetTickCount
  0138: GetModuleFileNameA
  005C: DeleteFileA
  009F: FindClose
  00AC: FindNextFileA
  00A3: FindFirstFileA
  012D: GetLastError
  00DA: GetCommandLineA
  0117: GetDriveTypeA
  0132: GetLogicalDriveStringsA
  001E: CloseHandle
  0037: CreateFileA
  02C3: Sleep
  01C5: InitializeCriticalSection
  005A: DeleteCriticalSection
  0153: GetProcAddress
  01DF: LoadLibraryA
  0290: SetEvent
  01DE: LeaveCriticalSection
  006F: EnterCriticalSection
  0252: ResetEvent
  02FD: WaitForSingleObject
  0034: CreateEventA
  02FB: WaitForMultipleObjects
  023D: ReadFile
  0263: SetCommState
  00D8: GetCommState
  0264: SetCommTimeouts
  01E9: LocalFree
  0174: GetSystemTime
  00C3: FreeLibrary
  0147: GetOverlappedResult
  030E: WriteFile
  01D0: IsBadReadPtr
  013A: GetModuleHandleA
  02F6: VirtualQuery
  0332: lstrcpynA
  01D3: IsBadWritePtr
  00BE: FormatMessageA
  02B8: SetUnhandledExceptionFilter
  01A8: GlobalMemoryStatus
  0113: GetDiskFreeSpaceA
  0172: GetSystemInfo
  0189: GetTimeZoneInformation
  0201: MulDiv
  0187: GetTimeFormatA
  010D: GetDateFormatA
  0099: FileTimeToSystemTime
  0098: FileTimeToLocalFileTime
  0120: GetFileAttributesA
  01C8: InterlockedDecrement

----------------------------------------



----------------------------------------


IMAGE_IMPORT_DESCRIPTOR - SIZE: 20
  Characteristics                  0x000924DC
  TimeDateStamp                    0x00000000
  ForwarderChain                   0x00000000
  Name                             0x000931DC
  FirstThunk                       0x0009039C

----------------------------------------

Imported from USER32.dll
  Hint  Function
-----------------------
  01F6: RegisterClassA
  00DF: GetActiveWindow
  0196: IsWindowVisible
  026F: ShowWindow
  0105: GetDlgItem
  010A: GetFocus
  0138: GetParent
  0213: SendDlgItemMessageA
  00B9: EnableWindow
  01D7: OffsetRect
  015A: GetWindowLongA
  017E: InvalidateRect
  00B1: DrawTextA
  01A2: LoadIconA
  0095: DialogBoxParamA
  0160: GetWindowRect
  022A: SetCursor
  0263: SetWindowTextA
  01EE: PtInRect
  0220: SetActiveWindow
  0234: SetForegroundWindow
  00D2: EnumWindows
  0166: GetWindowThreadProcessId
  0190: IsIconic
  019A: LoadAcceleratorsA
  0287: TranslateMessage
  0149: GetSystemMetrics
  005A: CreateWindowExA
  0296: UpdateWindow
  0284: TranslateAcceleratorA
  022C: SetCursorPos
  00D7: FindWindowA
  0233: SetFocus
  0276: SystemParametersInfoA
  000C: BeginPaint
  00BD: EndPaint
  0218: SendMessageA
  0221: SetCapture
  0206: ReleaseCapture
  0086: DefWindowProcA
  00FF: GetCursorPos
  020E: ScreenToClient
  0102: GetDesktopWindow
  00BB: EndDialog
  026B: ShowCursor
  00F3: GetClientRect
  0146: GetSysColor
  019E: LoadCursorA
  01CF: MsgWaitForMultipleObjects
  0097: DispatchMessageA
  0199: KillTimer
  0257: SetTimer
  02B3: wsprintfA
  0260: SetWindowPos
  0100: GetDC
  0207: ReleaseDC
  01E3: PostMessageA
  0230: SetDlgItemTextA
  010B: GetForegroundWindow
  01E1: PeekMessageA
  0156: GetWindow
  00F0: GetClassNameA
  025D: SetWindowLongA
  01C3: MessageBoxA
  01AF: LoadStringA
  008B: DestroyAcceleratorTable

----------------------------------------



----------------------------------------


IMAGE_IMPORT_DESCRIPTOR - SIZE: 20
  Characteristics                  0x00092148
  TimeDateStamp                    0x00000000
  ForwarderChain                   0x00000000
  Name                             0x00093328
  FirstThunk                       0x00090008

----------------------------------------

Imported from GDI32.dll
  Hint  Function
-----------------------
  00A2: ExtTextOutA
  0037: CreateFontA
  0191: MoveToEx
  020C: TextOutA
  01F8: SetTextAlign
  01D4: SetBkColor
  01FA: SetTextColor
  0172: GetTextExtentExPointA
  012D: GetDeviceCaps
  017E: GetTextMetricsA
  0054: DeleteObject
  0157: GetObjectA
  0038: CreateFontIndirectA
  002B: CreateCompatibleDC
  01CE: SelectObject
  0176: GetTextExtentPoint32A
  0051: DeleteDC
  015C: GetPaletteEntries
  0167: GetStockObject

----------------------------------------



----------------------------------------


IMAGE_IMPORT_DESCRIPTOR - SIZE: 20
  Characteristics                  0x00092140
  TimeDateStamp                    0x00000000
  ForwarderChain                   0x00000000
  Name                             0x00093342
  FirstThunk                       0x00090000

----------------------------------------

Imported from ADVAPI32.dll
  Hint  Function
-----------------------
  00F3: GetUserNameA

----------------------------------------



----------------------------------------


IMAGE_IMPORT_DESCRIPTOR - SIZE: 20
  Characteristics                  0x00092348
  TimeDateStamp                    0x00000000
  ForwarderChain                   0x00000000
  Name                             0x000933A8
  FirstThunk                       0x00090208

----------------------------------------

Imported from SHELL32.dll
  Hint  Function
-----------------------
  0063: SHGetPathFromIDListA
  008C: ShellExecuteA
  0027: FindExecutableA
  0066: SHGetSpecialFolderLocation

----------------------------------------



----------------------------------------


IMAGE_IMPORT_DESCRIPTOR - SIZE: 20
  Characteristics                  0x000925F8
  TimeDateStamp                    0x00000000
  ForwarderChain                   0x00000000
  Name                             0x000933B4
  FirstThunk                       0x000904B8

----------------------------------------

Imported from WSOCK32.dll
  Hint  Function
-----------------------
  Ord0015
  Ord0011
  Ord0073
  Ord0017
  Ord0014
  Ord000C
  Ord0009
  Ord0002
  Ord0006
  Ord0003
  Ord0074

----------------------------------------



----------------------------------------


IMAGE_IMPORT_DESCRIPTOR - SIZE: 20
  Characteristics                  0x000925E8
  TimeDateStamp                    0x00000000
  ForwarderChain                   0x00000000
  Name                             0x00093402
  FirstThunk                       0x000904A8

----------------------------------------

Imported from VERSION.dll
  Hint  Function
-----------------------
  0001: GetFileVersionInfoSizeA
  0000: GetFileVersionInfoA
  000A: VerQueryValueA

----------------------------------------

so the first thing is the ImageBase which is in the IMAGE_OPTIONAL_HEADER (which is very non-optional BTW)

the image base is 0x00400000, which is the default  for exe file so that's easy.

so we subtract that from the address ad we get 0x00042490
This is now a virtual address (aka VA) because it is an relative to the image base.

so looking through the IMAGE_SECTION_HEADERs we can see that the .text section has:
  VirtualSize                      0x0008E2EE
  VirtualAddress                0x00001000

which means it will be 0x00401000 -> 0x0048F2EE in memory ...

but anyway we can see that  1000 < 42490 < (1000+8E2EE)  so we know it's in this section.

so then we subtract the VirtualAddress 42490-1000 = 41490
this is the offset into the .text section for our address.

So then we just have to know where the text section is in the exe file, that is PointerToRawData

In this case Pointer to raw data is also 0x1000, same as virtual address so we just add 1000 back again and we get 42490 as the exe file offset.

This example is very easy because VirtualAddress=PointerToRawData.

If we wanted an address in the .rsrc section it would be different:

e.g.  0x004DA666
we have:
    ImageBase           =0x00400000
    VirtualAddress     =0x000D9000
    PointerToRawData =0x000AC000

so:
0x004DA666 - 0x00400000 - 0x000D9000 + 0x000AC000 = 0x000AD666 (exe file offset)

----------================-------------


END RESULT.... for all those ones in your mem dump there just remove the first '4' ;)

0x00442490 mem = 0x00042490 file

... but it's not always like that.


Title: Re: Nerd's Corner
Post by: shesycompany on February 16, 2018, 09:53:21 AM
nice info lamb!
Title: Re: Nerd's Corner
Post by: Lambchops on February 17, 2018, 02:47:47 AM
CALCULATING  TERRAIN TILE VALUES

So I'm up to the terraforming bit of this whole map editor thing, and this is as good a place as any to document it as I go. The wc2 game background is made up of blocks of 8x8 pixel data that are constructed into 32x32 pixel 'tiles'. The tile value for each map location is stored as a 16 bit value in PUD files (MTXM section).

I use 3 letter abbreviations to denote the different terrain types as follows:

Code: [Select]
LTW - light water
DKW - dark water 
LTM - light mud(coast)
DKM - dark mud 
LTG - light grass
DKG - dark grass
TRE - trees
ROC - rocks
HWL - human wall
OWL - orc wall

Each 32x32 tile can be made up of either 1 or 2 terrain types. Tiles with only 1 terrain type I call solid tiles. Tiles with 2 terrain types I call border tiles.

NUMERICAL FORMAT

All tiles are stored as 16bit values, with the information encoded as a sequence of nibbles (4 bits). There are multiple versions of each tile which have slightly different graphics to create a more natural look to the map. For all tiles this pictorial variant is stored in the least significant nibble (bits 0-3) and these 4 bits have no other relevance to the game mechanics.

Code: [Select]
i.e.
0x0050 LTG variant 0
0x0051 LTG variant 1
0x0055 LTG variant 5
etc.

"FILLER" TILES

The light and dark mud and grass tiles have variants depicting objects - rocks plants skulls etc. numbered as follows:

Code: [Select]
LTG/DKG - 0-2 Plain Solid
LTG/DKG - 4-9 Filler Solid
LTM/DKM - 0-3 Plain Solid
LTM/DKM - 4-B Filler Solid
i.e. 0x0057 = LTG 4th filler tile (the one with the big rock)

Unused values for the variant nibble will be mapped as repeats of the other solid tiles.

SOLID TILE VALUES
Code: [Select]
0x001v - LTW
0x002v - DKW
0x003v - LTM
0x004v - DKM
0x005v - LTG
0x006v - DKG
0x007v - TRE
0x008v - ROC
0x009v - OWL (Single)
0x00Av - HWL (Single)
0x00Bv - OWL (central)
0x00Cv - HWL (central)
Where v designates the graphics variant.

SOLID WALL VARIANTS

Code: [Select]
v=0-1 Full
v=2   Damaged
v=3   Full
v=4   Destroyed
v=5-F Full

BORDER TILES

Border tiles are made up of 2 different terrain types. Not all terrain can co-exist on a border tile. Acceptable combinations are:

Code: [Select]
Value    (0) (1)
0x01Lv - LTW/DKW
0x02Lv - LTM/LTW
0x03Lv - LTM/DKM
0x04Lv - LTM/ROC
0x05Lv - LTG/LTM
0x06Lv - LTG/DKG
0x07Lv - LTG/TRE
Where v designates the graphics variant.
Where L designates the layout.

For border tiles the 2nd nibble represents the layout. Each bit in the nibble represents one quater of the tile.

Code: [Select]
  bit0 - bit1
   |      |
  bit2 - bit3

So for a grass/tree border tile like this:

Code: [Select]
TG
TT
(all trees except grass in the top right)
the bit values are

Code: [Select]
10
11

= 1101 binary

as border tile layouts dont represent solid tiles, the first value is 0001 not 0000 - which would be solid, however they are stored starting with 0 so at this point all values must have 1 subtracted from them

= 13 - 1
= 12   ( 0x0C )

so using 0x07Lv - LTG/TRE

this tile would be 0x07C0
or 0x07C1 for the other variant.

*border tiles have 2 variants each for corners and 3 variants for straight edges.

JOINED WALL TILES

Code: [Select]
0x08Lv - HWL Joined
0x09Lv - OWL Joined

The layout of joined wall tiles:

Code: [Select]
BIT  2
   3 # 1
     0

So for a 3-way join between walls left, right and below we need bits 3,1,0... so:
binary 1011 = decimal 11 (0x0B) -1 = decimal 10 (0x0A)

so OWL like this:
Code: [Select]
###
 #
= 0x09A0

*corners/joins have 1 variant straight joined walls (above&below or left&right) have 2 variants.

Title: Re: Nerd's Corner
Post by: shesycompany on February 18, 2018, 03:35:19 PM
opps having to much fun...but i think i have may located units.

found some old dos stuff this is some kinda mod...not played it yet anyone knew these people?

and i believe units are here as i had every icon upgrading to a town hall...which is stats not a grp change.

and yes peons will go to it:P

well i can successfully hop out a foot archer or balista on paladin spot ..and put all units in the game and it has thier prices icon but it will not allow it to be made as some other part is stopping it....

what i think its doing is sending me back to the barracks to call it a orc barracks before a grunt can be made value, idk i hope not it cant be that dam difficult.

keep up with the good work lamby.
Title: Re: Nerd's Corner
Post by: Lambchops on February 19, 2018, 03:13:46 PM
Almost ready for an alpha test of the basic editor. Have the terrain / terraforming / unit placement working reasonably well. Everything works at any zoom, so you can even view a large map full screen and still edit it. Can place half terrain tiles - like thin rivers etc.  :fro:

Havn't done a mini-map yet and it really doesn't need one - you just zoom in/out with the mouse wheel at any time. Will probably add one at some point I guess but it's not at the top of the list.

Still have a half-page TO DO list of things to tweak. Hopefully I'll get those done tomorrow then I'll need some testers (@easycompany and @tupac spring to mind :) ).

Still haven't done any unit editing - starting conditions ... etc. etc. although all that + all the tricks can be added once the basic GUI is nice and tight....  At the moment it does pretty much everything my old editor can't do and none of the things that it can lol.

 :critter:






Title: Re: Nerd's Corner
Post by: Delete mine too on February 19, 2018, 10:12:22 PM
Almost ready for an alpha test of the basic editor. Have the terrain / terraforming / unit placement working reasonably well. Everything works at any zoom, so you can even view a large map full screen and still edit it. Can place half terrain tiles - like thin rivers etc.  :fro:

Havn't done a mini-map yet and it really doesn't need one - you just zoom in/out with the mouse wheel at any time. Will probably add one at some point I guess but it's not at the top of the list.

Still have a half-page TO DO list of things to tweak. Hopefully I'll get those done tomorrow then I'll need some testers (@easycompany and @tupac spring to mind :) ).

Still haven't done any unit editing - starting conditions ... etc. etc. although all that + all the tricks can be added once the basic GUI is nice and tight....  At the moment it does pretty much everything my old editor can't do and none of the things that it can lol.

 :critter:







I'll test the shit out of it. Spawn the beta ;)
Title: Re: Nerd's Corner
Post by: shesycompany on February 20, 2018, 02:49:27 AM
if u didt get that szawg i dont know how else to tell ya
Title: Re: Nerd's Corner
Post by: Szwagier on February 20, 2018, 11:16:44 AM
if u didt get that szawg i dont know how else to tell ya
Maybe im blind, but where did u change missing objective  build 6 farms not 4??
Title: Re: Nerd's Corner
Post by: shesycompany on February 20, 2018, 11:55:26 AM
naw i deleted dam it ..someday im gonna drink beer...we got a bigger mission...making units....well ill make it my goal,

ask tupac he messed with them at one time maybe in his sticky


---maybe a peon seeting in pud would allow it to build no idea.. just for lookage for now

lots of values if u  want to hex ill put u in the spot, so we can find out what everything is.
Title: Re: Nerd's Corner
Post by: Lambchops on March 25, 2018, 11:46:24 PM
ALLIED COLORS ON MINI-MAP


This one was another idea from Nedro, it makes all allies blue and all enemies red on the mini-map.

You can toggle it on/off by pushing F2.


(http://forum.war2.ru/index.php?action=dlattach;topic=2703.0;attach=2177)
Title: Re: Nerd's Corner
Post by: Delete mine too on March 26, 2018, 07:43:34 AM
ALLIED COLORS ON MINI-MAP


This one was another idea from Nedro, it makes all allies blue and all enemies red on the mini-map.

You can toggle it on/off by pushing F2.


([url]http://forum.war2.ru/index.php?action=dlattach;topic=2703.0;attach=2177[/url])


I like that!!!
Title: Re: Nerd's Corner
Post by: Lambchops on March 26, 2018, 09:38:32 AM
I like that!!!

Cool. I assume it worked for you?

There's one case with windows 8 that I know of where it won't work. Probably some stupid windows security thing that is stopping it writing to the wc2 process. It works on XP and 7 so far.
Title: Re: Nerd's Corner
Post by: Lambchops on August 21, 2018, 02:34:04 AM
@tupac @iL

No-CD crack ....

War2noCDloader.exe not needed


--------------
No-CD Patch

File offset 0x2877F
old: E8:2C:06:00:00
new: 90:90:90:90:90
(5 bytes)

File offset 0x2878D
old: 75
new: 74
(1 byte)
-----------------


My first attempt worked but flagged the game as a spawned version so half the stuff was knobbled.
This version seems to work properly.

>>>> Please Test <<<<


----  EDIT ----

Been using it for a couple of weeks now, works for me :)


-- edit -- edit ---

Oh. Tupac has pointed out that this does not work for single player campaigns - only for multiplayer. I will have to look into that when I get some spare time  :-\


-- edit -- edit -- edit --


OK forget all that stuff, just change the byte at 0x28E17 from 0x01 to 0x00  :thumbsup:



Title: Re: Nerd's Corner
Post by: Lambchops on September 16, 2018, 05:00:03 AM
OK I have finally done a little bit more on PUDPIC.

You can get the new version HERE (http://forum.war2.ru/index.php?action=dlattach;topic=4126.0;attach=2576).


I wrote an ASM image resize/blend procedure so it can produce a pic of the size you want. Also has a jpeg save option.

i.e.

    PUDPIC /s:500  MyMap.pud

will make a 500x500 32 bit blended bitmap

Without the /s switch it will default to producing a full size 8bit bitmap with the original game palette (the current behavior).

   PUDPIC /j:80 ThisMap.pud

will save the full size 8 bit image as a quality 80 jpeg

   PUDPIC /s:1024 /j:90 Maposaurus.pud

will resize to 1024x1024 and save as quality 90 .jpg file

 ^- THESE SETTINGS SEEM TO BE PRETTY GOOD FOR A GENERAL PURPOSE POST ON FORUM/DISCORD ETC IMAGE
( give you around a 300KB file that looks ok if you dont zoom in too close)




... also if you want you can just rename the exe file to include the size/quality.

i.e.  if you rename it to "PUDPICs500.exe" it will automatically make a 500x500 bitmap any time you drop a file on it.

or if you rename it to "PUDPICs1024j90.exe" it will automatically make a 1024x1024 quality 90 jpeg any time you drop a file on it.

You can even have multiple copies of the exe file with different sizes you use and just drop your pud file on the one you want.

Like this:

(http://forum.war2.ru/index.php?action=dlattach;topic=4126.0;attach=2577)


I *think* the command line switches will work in a UNICODE environment - but please let me know if you have any problems.

Have fun  :critter:


Title: Re: Nerd's Corner
Post by: Cel on October 09, 2018, 09:26:22 AM
@Lambchops May we have the sources of that nice little program of yours?  (The PUDPIC program) ^-^
Title: Re: Nerd's Corner
Post by: Lambchops on October 10, 2018, 08:04:20 PM
@Lambchops May we have the sources of that nice little program of yours?  (The PUDPIC program) ^-^


Yeah I dont mind sharing, but it's a pretty tangled mess of code ... 2 ASM dll projects and C++ project that uses the dlls

The C++ is from a half written pud editor that still has lots of stuff not used by the pudpic program.

Its about 130 source files in all. A lot of that is just all the WC2 graphics repackaged into LambRES.dll


>> What do you want to do with it?


Probably your easiest path to drawing WC2 stuff is to call the functions from the 2 dll files:

Code: [Select]

// This stuff in .h file  <-----

extern "C" { 
    typedef struct pudsect {
        DWORD Reserved;
        DWORD name;
        DWORD size;
        LPVOID data;
    }PUDSECT;
}

extern "C" { 
    typedef struct hmibmp {
        BITMAPFILEHEADER* pFile;
        BITMAPINFOHEADER* pInfo;
        RGBQUAD*          pPal;
        BYTE*             pBits;
        int               width;
        int               height;
        int               bpp;
        int               linew;
        int               usage;
        int               size;
    }HMIBMP;
}


// LambRES.dll
extern "C" typedef CHAR*   (__stdcall *rfngetname )(int utype);
extern "C" typedef LPVOID  (__stdcall *rfntileset )(int ntileset);
extern "C" typedef LPVOID  (__stdcall *rfngetpal  )(int npalette);
extern "C" typedef LPVOID  (__stdcall *rfngetgrp  )();


//PUDfile.inc
extern "C" typedef LPVOID  (__stdcall *pfnpudload )(CHAR* path);
extern "C" typedef int     (__stdcall *pfnpudsave )(LPVOID hpud,CHAR* path);

//PUDpud.inc
extern "C" typedef int     (__stdcall *pfnsectcnt )(LPVOID hpud);
extern "C" typedef void    (__stdcall *pfndestroy )(LPVOID hpud);
extern "C" typedef LPVOID  (__stdcall *pfndelsect )(LPVOID hpud,LPVOID hsect);
extern "C" typedef PUDSECT*(__stdcall *pfnfindsect)(LPVOID hpud,DWORD sectname);
extern "C" typedef int     (__stdcall *pfnupdsect )(LPVOID hpud,LPVOID hsect,LPVOID lpnew,int nbytes);
extern "C" typedef PUDSECT*(__stdcall *pfngetsect )(LPVOID hpud,int nsect);
extern "C" typedef int     (__stdcall *pfnsectndx )(LPVOID hpud,DWORD sectname);
extern "C" typedef LPVOID  (__stdcall *pfnsectset )(LPVOID hpud,LPVOID hsect,int nsect);
extern "C" typedef BOOL    (__stdcall *pfnsectcre )(LPVOID hpud,DWORD sectname,LPVOID lpnew,int nbytes);
extern "C" typedef LPVOID  (__stdcall *pfnrealloc )(PUDSECT* hSect,int nbytes);

//PUDunit.inc
extern "C" typedef int     (__stdcall *pfnunitsize)(int utype);
extern "C" typedef int     (__stdcall *pfnuniticof)(int utype);
extern "C" typedef int     (__stdcall *pfnlistget )(int list,int ndx);
extern "C" typedef int     (__stdcall *pfnlistnext)(int list,int utype);
extern "C" typedef int     (__stdcall *pfnlistprev)(int list,int utype);
extern "C" typedef LPVOID  (__stdcall *pfnlistname)(int list);

//PUDtile.inc
extern "C" typedef void    (__stdcall *pfnrndrmap )(LPVOID hbmp,LPVOID mtxm,int mapw);
extern "C" typedef void    (__stdcall *pfnrndrtile)(LPVOID hbmp,int tile,int x,int y);
extern "C" typedef LPVOID  (__stdcall *pfngettile )(int tile);
extern "C" typedef void    (__stdcall *pfntileset )(LPVOID tileset);
extern "C" typedef void    (__stdcall *pfnblack   )(HDC dc,int x,int y,int w,int h);

//hmibmp.inc
extern "C" typedef HMIBMP* (__stdcall *pfnmakebmp )(int w,int h,int bpp);
extern "C" typedef void    (__stdcall *pfnfreebmp )(HMIBMP* bmp);
extern "C" typedef int     (__stdcall *pfnzerobmp )(HMIBMP* bmp);
extern "C" typedef void    (__stdcall *pfnsavebmp )(CHAR* path,HMIBMP* bmp);
extern "C" typedef void    (__stdcall *pfnsavejpg )(CHAR* path,HMIBMP* bmp,int quality);
extern "C" typedef void    (__stdcall *pfnperfbmp )(HMIBMP* bmp);
extern "C" typedef void    (__stdcall *pfncopyimg )(HMIBMP* src,int scrx,int srcy,int srcw,int scrh,HMIBMP* dst,int dstx,int dsty,int transp);
extern "C" typedef int     (__stdcall *pfncopyfull)(HMIBMP* dstbmp,HMIBMP* srcbmp,int transp);
extern "C" typedef void    (__stdcall *pfndispimg )(HDC destDC,int x,int y,int w,int h,HMIBMP* bmp,int dx,int dy,int dw,int dh);
extern "C" typedef void    (__stdcall *pfnsetpal  )(HMIBMP* bmp,LPVOID palette);
extern "C" typedef void    (__stdcall *pfndrawrect)(HMIBMP* bmp,int x,int y,int w,int h,int color);
extern "C" typedef HMIBMP* (__stdcall *pfnsizebmp )(HMIBMP* bmp,int w,int h);

//PUDgrp.inc
extern "C" typedef LPVOID  (__stdcall *pfngrpinit )(LPVOID grplubase);
extern "C" typedef void    (__stdcall *pfndrawgrp )(int grp,int nframe,LPVOID daddr,int dwidth,int owner,int centre,int mirror);
extern "C" typedef void    (__stdcall *pfndrawbtn )(LPVOID bmp, int xpos, int ypos, int icon, int state);




extern rfngetname      RESgetName;
extern rfntileset      RESgetTileset;
extern rfngetpal       RESgetPalette;
extern rfngetgrp       RESgetGrp;

extern pfnpudload      PUDload;
extern pfnpudsave      PUDsave;

extern pfnsectcnt      PUDsection_count;
extern pfndestroy      PUDdestroy;
extern pfndelsect      PUDdelete_section;
extern pfnfindsect     PUDfind_section;
extern pfnupdsect      PUDupdate_section;
extern pfngetsect      PUDget_section;
extern pfnsectndx      PUDsection_index;
extern pfnsectset      PUDsection_set_index;
extern pfnsectcre      PUDcreate_section;
extern pfnrealloc      PUDsection_realloc;

extern pfnunitsize     PUDunitSize;
extern pfnuniticof     PUDunitIconFrame;
extern pfnlistget      PUDlistGet;
extern pfnlistnext     PUDlistNext;
extern pfnlistprev     PUDlistPrev;
extern pfnlistname     PUDlistName;

extern pfnrndrmap      PUDrenderMap;
extern pfnrndrtile     PUDrenderTile;
extern pfngettile      PUDgetTile;
extern pfntileset      PUDtileset;
extern pfnblack        PUDblack;

extern pfnmakebmp      make_bitmap;
extern pfnfreebmp      free_bitmap;
extern pfnzerobmp      zero_bitmap;
extern pfnsavebmp      save_bitmap;
extern pfnsavejpg      save_jpeg;
extern pfnperfbmp      perforate_bitmap;
extern pfncopyimg      copy_image;
extern pfncopyfull     copy_full_image;
extern pfndispimg      display_image;
extern pfnsetpal       set_palette;
extern pfndrawrect     draw_rect;
extern pfnsizebmp      size_bitmap;

extern pfngrpinit      GRPinit;
extern pfndrawgrp      GRPdraw;
extern pfndrawbtn      GRPdrawButton;


///////////////////////////////////////////////////////////////////////////////

// This stuff in .cpp file   <-------



HMODULE hResDll  = LoadLibraryA("LambRES");
HMODULE hLambDll = LoadLibraryA("LambWC2");


rfngetpal   RESgetPalette       = (rfngetpal  )GetProcAddress(hResDll , "RESgetPalette"       );
rfngetgrp   RESgetGrp           = (rfngetgrp  )GetProcAddress(hResDll , "RESgetGrp"           );
rfngetname  RESgetName          = (rfngetname )GetProcAddress(hResDll , "RESgetName"          );
rfntileset  RESgetTileset       = (rfntileset )GetProcAddress(hResDll , "RESgetTileset"       );


pfnpudload  PUDload             = (pfnpudload )GetProcAddress(hLambDll, "PUDload"             );
pfnpudsave  PUDsave             = (pfnpudsave )GetProcAddress(hLambDll, "PUDsave"             );

pfnsectcnt  PUDsection_count    = (pfnsectcnt )GetProcAddress(hLambDll, "PUDsection_count"    );
pfndestroy  PUDdestroy          = (pfndestroy )GetProcAddress(hLambDll, "PUDdestroy"          );
pfndelsect  PUDdelete_section   = (pfndelsect )GetProcAddress(hLambDll, "PUDdelete_section"   );
pfnfindsect PUDfind_section     = (pfnfindsect)GetProcAddress(hLambDll, "PUDfind_section"     );
pfnupdsect  PUDupdate_section   = (pfnupdsect )GetProcAddress(hLambDll, "PUDupdate_section"   );
pfngetsect  PUDget_section      = (pfngetsect )GetProcAddress(hLambDll, "PUDget_section"      );
pfnsectndx  PUDsection_index    = (pfnsectndx )GetProcAddress(hLambDll, "PUDsection_index"    );
pfnsectset  PUDsection_set_index= (pfnsectset )GetProcAddress(hLambDll, "PUDsection_set_index");
pfnsectcre  PUDcreate_section   = (pfnsectcre )GetProcAddress(hLambDll, "PUDcreate_section"   );
pfnrealloc  PUDsection_realloc  = (pfnrealloc )GetProcAddress(hLambDll, "PUDsection_realloc"   );


pfnunitsize PUDunitSize         = (pfnunitsize)GetProcAddress(hLambDll, "PUDunitSize"         );
pfnuniticof PUDunitIconFrame    = (pfnuniticof)GetProcAddress(hLambDll, "PUDunitIconFrame"    );
pfnlistget  PUDlistGet          = (pfnlistget )GetProcAddress(hLambDll, "PUDlistGet"          );
pfnlistnext PUDlistNext         = (pfnlistnext)GetProcAddress(hLambDll, "PUDlistNext"         );
pfnlistprev PUDlistPrev         = (pfnlistprev)GetProcAddress(hLambDll, "PUDlistPrev"         );
pfnlistname PUDlistName         = (pfnlistname)GetProcAddress(hLambDll, "PUDlistName"         );

pfnrndrmap  PUDrenderMap        = (pfnrndrmap )GetProcAddress(hLambDll, "PUDrenderMap"        );
pfnrndrtile PUDrenderTile       = (pfnrndrtile)GetProcAddress(hLambDll, "PUDrenderTile"       );
pfngettile  PUDgetTile          = (pfngettile )GetProcAddress(hLambDll, "PUDgetTile"          );
pfntileset  PUDtileset          = (pfntileset )GetProcAddress(hLambDll, "PUDtileset"          );
pfnblack    PUDblack            = (pfnblack   )GetProcAddress(hLambDll, "PUDblack"            );

pfnmakebmp  make_bitmap         = (pfnmakebmp )GetProcAddress(hLambDll, "make_bitmap"         );
pfnfreebmp  free_bitmap         = (pfnfreebmp )GetProcAddress(hLambDll, "free_bitmap"         );
pfnzerobmp  zero_bitmap         = (pfnzerobmp )GetProcAddress(hLambDll, "zero_bitmap"         );
pfnsavebmp  save_bitmap         = (pfnsavebmp )GetProcAddress(hLambDll, "save_bitmap"         );
pfnsavejpg  save_jpeg           = (pfnsavejpg )GetProcAddress(hLambDll, "save_jpeg"           );
pfnsizebmp  size_bitmap         = (pfnsizebmp )GetProcAddress(hLambDll, "size_bitmap"         );
pfnperfbmp  perforate_bitmap    = (pfnperfbmp )GetProcAddress(hLambDll, "perforate_bitmap"    );
pfncopyimg  copy_image          = (pfncopyimg )GetProcAddress(hLambDll, "copy_image"          );
pfncopyfull copy_full_image     = (pfncopyfull)GetProcAddress(hLambDll, "copy_full_image"     );
pfndispimg  display_image       = (pfndispimg )GetProcAddress(hLambDll, "display_td_image"    );
pfnsetpal   set_palette         = (pfnsetpal  )GetProcAddress(hLambDll, "set_palette"         );
pfndrawrect draw_rect           = (pfndrawrect)GetProcAddress(hLambDll, "draw_rect"           );

pfngrpinit  GRPinit             = (pfngrpinit )GetProcAddress(hLambDll, "GRPinit"             );
pfndrawgrp  GRPdraw             = (pfndrawgrp )GetProcAddress(hLambDll, "GRPdraw"             );
pfndrawbtn  GRPdrawButton       = (pfndrawbtn )GetProcAddress(hLambDll, "GRPdrawButton"       );




The pud load/save routines and format are from HERE (http://forum.war2.ru/index.php/topic,2852.msg48015.html#msg48015)



Make sure you first do:

Code: [Select]
PUDtileset(RESgetTileset(0));
GRPinit(RESgetGrp());


This sets some internal pointers, otherwise you will get GP faults if you try to use stuff.


I have to go out right now, I can give you more info later when I have more time.
Title: Re: Nerd's Corner
Post by: Lambchops on October 11, 2018, 05:59:36 AM
@Cel

Ok so the HMIBMP structure is what I use internally to handle bitmaps.

Its just a conveniant way to handle device independent bitmaps without having to get bogged down with a lot of the unnecessary/unused stuff, although you can still get to the underlying windows structures if you need to.


It has these members:

Code: [Select]
pFile        pointer to the BITMAPFILEHEADER struct
pInfo        pointer to the BITMAPINFOHEADER struct
pPal         pointer to the palette (if the bitmap has one)
pBits        pointer to the pixmap (actual pixel data - depends on the format)
width        duh
height       duh
bpp          bits per pixel (this will be 8 for most WC2 things)
linew        internal size in bytes for one line of pixels
usage        (pixel color values or palette entries)
size         total size of all structures


so if you do:

Code: [Select]
HMIBMP* MyBmp = make_bitmap(300,200,8);

You will get a handle to a 300x200 8-bit bitmap. All the underlying windows structures are created automatically.

when finished use:

Code: [Select]
free_bitmap(MyBmp);

to deallocate all the memory.

*** These bitmap functions are not complete for every format, I have just added to them whenever I needed to do something .... most of it works for 8-bit bitmaps - because that's what I mostly play with for WC2 stuff. Some things work for 32 or 24 bit bitmaps. Pretty much none of it will work for 4 or 16 bit bmps (but who cares about that crap lol). ***

For WC2 stuff you will just want 8-bit bmps, the only thing you would use any other format for is the size_bitmap() func which will resize an 8-bit bmp and blend the colors then return a 32-bit bitmap of the requested size.

Code: [Select]
LPVOID MyPud = PUDload("c:\\someMap.pud");

Will return a handle to a linked list of PUDSECT structures, which contain pointers to the actual data for each section.

You can get a pointer to the data for a given section like this:

Code: [Select]
BYTE* sectionData(LPVOID hPud, DWORD sname){
    PUDSECT* sptr = PUDfind_section(hPud,sname);
    if (sptr!=NULL) return sptr->data;
    return NULL;
}

NOTE: the section name is a DWORD not a string .... all pud section names are 4 bytes, so you want constants like this:


Code: [Select]
#define sTYPE 0x45505954 // "TYPE"
#define sVER_ 0x20524556 // "VER "
#define sDESC 0x43534544 // "DESC"
#define sOWNR 0x524E574F // "OWNR"
#define sERA_ 0x20415245 // "ERA "
#define sERAX 0x54415245 // "ERAX"
#define sDIM_ 0x204D4944 // "DIM "
#define sUDTA 0x41544455 // "UDTA"
#define sUNIT 0x54494E55 // "UNIT"
#define sUGRD 0x44524755 // "UGRD"

#define sSIDE 0x45444953 // "SIDE"
#define sSGLD 0x444C4753 // "SGLD"
#define sSLBR 0x52424C53 // "SLBR"
#define sSOIL 0x4C494F53 // "SOIL"
#define sAIPL 0x4C504941 // "AIPL"

#define sMTXM 0x4D58544D // "MTXM"
#define sSQM_ 0x204D5153 // "SQM "
#define sOILM 0x4D4C494F // "OILM"
#define sREGM 0x4D474552 // "REGM"

#define sSIGN 0x4E474953 // "SIGN"
#define sALOW 0x574F4C41 // "ALOW"


so you can get the map size of a pud file from the "DIM " section like:

Code: [Select]
int getPudDim(LPVOID hpud){
    WORD* pdim = (WORD*) sectionData(hpud,sDIM_)
    if (pdim) return (int) *pdim;
    return 0;
}

If you get a "tile" value from the MTXM section you can draw that square of terrain on the bitmap at (x,y) with:

Code: [Select]
PUDrenderTile(MyBmp, tileValue , int x, int y);

or

Code: [Select]
PUDrenderMap(MyBmp, MTXM_section, size);

will do the terrain for the whole map - but make sure the bitmap is the right size or you will crash.


The different terrain styles can be selected like this:

Code: [Select]
#define FOREST     0
#define WINTER     1
#define WASTELAND  2
#define SWAMP      3

PUDtileset(RESgetTileset( WINTER ));

you will also need to set the appropriate palette in your bitmap or the colors will come out wrong.

Code: [Select]
set_palette(MyBmp , RESgetPalette( WINTER ));


so you should be able to make a bmp file of just the terrain for a PUD file with something like:

Code: [Select]
//     # UNTESTED # - probably has errors/typos

#include <windows.h>
//#include HEADER FILE WITH IMPORT DEFS FROM PREVIOUS POST AND CONSTANT DEFS (ABOVE)



CHAR* pudpath = "myMap.pud";
CHAR* bmppath = "this.bmp";


// load the pud file
LPVOID hPud = PUDload(pudpath);


BYTE* sectionData(LPVOID hpud, DWORD sname){
    PUDSECT* sptr = PUDfind_section(hpud,sname);
    if (sptr!=NULL) return (BYTE*)sptr->data;
    return NULL;
}

int getPudSize(LPVOID hpud){
    WORD* pdim = (WORD*) sectionData(hpud,sDIM_);
    if(pdim) return (int) *pdim;
    return 0;
}

int getTerrainType(LPVOID hpud){
    WORD* pter = (WORD*) sectionData(hpud,sERA_);
    if(pter) return (int) *pter;
    return 0;
}


// get some info from the pud
int   mapsize = getPudSize(hPud);
int   terrain = getTerrainType(hPud);


// make a bitmap in memory (tiles are 32x32 pixels)
HMIBMP* hbm = make_bitmap(mapsize*32,mapsize*32,8);

// use the tiles for the map terrain type
PUDtileset(RESgetTileset(terrain));

// don't forget this if you are using GRPs, only needs to be done once to initialize
// can't remember if it needs to be done for only the terrain, but it cant hurt lol
GRPinit(RESgetGrp());

//paste all the tile graphics for the pud onto the bitmap
PUDrenderMap( hbm, sectionData(hpud,sMTXM) , mapsize);


// ensure the bmp file has the correct palette for the terrain type
set_palette(hbm , RESgetPalette( terrain ));

// save the bitmap to a file
save_bitmap(bmppath,hbm);

// dispose of the bitmap
free_bitmap(hbm);

// dispose of the pud structure
PUDdestroy(hPud);


Obviously you will also need the two dlls from PUDPIC, #define statements for used constants, and the function import stuff and structure defs from the previous post.

Play with that stuff and let me know how you go ....      HF :)




p.s. also if you want you can display your bitmap (or part of it) on a Windows device context with:

Code: [Select]

display_image( dc, windowX, windowY, displayWidth, displayHeight, hbm, bmX, bmY, bmW, bmH   );


if you pass 0 for the width and height they will default to the bitmap width and height, so:
Code: [Select]
display_image(dc,0,0,0,0,hbm,0,0,0,0);
will just display the bitmap on the window without any resizing.

                                                                                               :critter:
Title: Re: Nerd's Corner
Post by: Cel on October 11, 2018, 08:07:56 AM
Are these sources somewhere on Github? That would be much handier to read/propose changes or additions :-)

That would help having a global view of the thing too.
I do love C++, ASM is readable I just wonder why work with assembly in the first place, it is very low level and tedious to make even small things  ;D.
But hey what ever works for ya is fine  ^-^

The reason is, I checked your archive and it is flagged as malicious by most common anti viruses, they find a trojan-like pattern/signature in the program which may be avoided.
Given the nature and the simplicity of the program (opening a file and parsing binary / creating an image and saving it) I wanted to see if we could try and find a way to fix the issue.

Also I thought if we have it on Github  maybe I and others could try and help you improve the thing by proposing changes (pull requests, merges, branching all that beauty) to add new features to the thing and/or fix track issues.

The virus detection matters because even if we know it is perfectly safe if we want to put it in the downloads section of the site for everyone to find easily, and google runs a basic automated test like they always do on hosted files, they will flag the whole war2.ru site as malicious, as it happened before. And it is a mess after to make them roll back on these things.

Do you think it could be a good idea? :-)

 :critter:

edit: Also it is a shame we do not have the sources of Alexander cech he did something around these lines (PudImage) and Wardraft which was a map editor that allowed a bit more pud manipulations. :-)
Title: Re: Nerd's Corner
Post by: Lambchops on October 11, 2018, 10:41:05 AM
The reason is, I checked your archive and it is flagged as malicious by most common anti viruses,


PFFFFFFFF (http://forum.war2.ru/index.php/topic,2703.msg50633.html#msg50633)
^Read this^

If anyone wants to actually put any work into programming I am always the first person to help. I have already spent quite a few hours of my time in reply to your request (YOU'RE WELCOME).

I sometimes publish source to try to help people, but mostly I don't do it for 2 reasons:

   1) Vanity

Most programming jobs involve using personal libraries of code and mashing together various bits that I have been writing my entire life.

To publish the source fpr a specific app I would want to go through it all and cut out all the bits that aren't needed for that app, and make sure that there isn't any noobish trashy things I wrote 20 years ago, and I would be embarrassed to have people see without re-writing them properly.

Also source code often ends up with random notes and comments, non-functional first-attempts at things commented out or not... even notes from phone calls I answered while coding.

It can be very time consuming to check, reorganise and sometimes re-write thousands of lines of code to make it appropriate for public viewing. Just publishing hundreds of source files is like emptying out your underwear draw in a public place.

   2) Why would I bother?

Sorry, but quite honestly I've been publishing a large amount of information about programming and the WC2 client for years now, and I'm yet to see one single line of source code that anyone else has written that has helped me with anything.

I have attempted to collaborate with others before and the only thing that happened is I wasted a heap of hours and nobody else contributed anything.

My first thought when you asked for the source was "sure, why not?"

Then I started looking through all the source files for the 3 different elements of PUDPIC and realised it was probably going to take a couple of days to vet and re-assemble the entire lot into a publishable collection and thought... meh - none of these people ever do anything with any of it, why would I waste my time?

If anyone actually wants to do something with it, there is lots to work with here .... go for it!
If anyone can't ....or more likely can't be bothered, to work out even the small amount I have posted here, then there is no way they will ever do anything useful with the rest.

Want to do some programming? Great... there's a BIG start. How about you post your source here and I will help you with it ok? If you can get you own a version of PUDPIC working I will find a way to make the dlls acceptable... the only issue might be copyright because they contain pretty much all the graphics for the game. :-\


The virus detection matters because even if we know it is perfectly safe if we want to put it in the downloads section of the site for everyone to find easily, and google runs a basic automated test like they always do on hosted files, they will flag the whole war2.ru site as malicious, as it happened before.


This is a valid issue, if anyone running the server asked me about this because they wanted to host my progs, I would try to find a solution. For PUDPIC probably just uncompressing the files might work, idk I havn't even looked at it because nobody has ever suggested that.

Some things I am less comfortable exposing because they work with the WC2 exe and could potentially be exploited for hacks, but PUDPIC only works with pud files so there is no issue there.


Are these sources somewhere on Github? That would be much handier to read/propose changes or additions  .... / snip /.... Do you think it could be a good idea? :-)


This would be really nice. It would mean a lot of work for me, which I would be much more inclined to do if I thought there was any chance at all that anyone else would actually contribute anything, but going on past experience, that is very unlikely.



         ------------------------------

Just while I'm on the subject .... if there is anyone here paranoid enough to actually be concerned about any real malware in any of my stuff, here's a couple of points to ponder:

All you have to do to spot a trojan is firewall it... if its doing anything nasty it will try to phone home... otherwise what's the point?

...and if you actually think that:

a) I am the type of person that would invade people's privacy for my own petty ends
         or
b) that even if I was that kind of person, that I care enough about anyone here's personal life (or even WC2 life) to bother,

.... then the answer is very easy: don't use my programs, and also eat a large bag of dicks :)

Title: Re: Nerd's Corner
Post by: Cel on October 11, 2018, 12:20:14 PM
Well that is the thing with Github you dont host the image files nor do you want to host the binary files, just the sources so no copyright issues there because images and the archives are not included  ^-^

You don't have to bother making your sources look good, unless you really want to use these as a way to get noticed by employers or because you want that to be part of your resume or portfolio. <= which also could be quite a good idea but that is indeed more work

Really if not for the above it is most of the time the matter of two clicks.

The benefits are that sometimes external views see things you might have missed.

Most of us have jobs that don't include warcraft 2, but sometimes we take one or two hours to read some foreign code there and there.
Yes nothing may come out of it but sometimes it does.

I guess these names sound familiar to you:
Daniel Lemberg.
Simon Pelsser.
Lasse Jensen.
These dudes worked on analysing the pud format because of their work it is much easier for people like us to play around with it.
Many others like Alexander Cech did programs that did prettymuch the same things like pudImage.exe and the famous Wardraft.exe

Had we got the sources from these utilities for example maybe we wouldn't have to reinvent the wheel every time, just the tires maybe :P

the strength of open source is that even if you let your project  sit out there and stop working on it someone might one day dig it out and use it as a base for something else.

Now that is your choice, in the end you do what you want just saying if you had your sources out there I would have had a look by curiosity :P

:critter:
Title: Re: Nerd's Corner
Post by: Lambchops on October 11, 2018, 10:49:14 PM
nless you really want to use these as a way to get noticed by employers or because you want that to be part of your resume or portfolio. <= which also could be quite a good idea but that is indeed more work

Exactly, and perhaps taking a small amount of pride in my work?
Title: Re: Nerd's Corner
Post by: Lambchops on October 13, 2018, 03:20:27 AM
So for future reference here's a working re-written version of PUDPIC.exe

It draws the terrain and the units.

It doesn't process command line switches or passed filename, just uses the filenames: "this.pud" "this.bmp", and "this.jpg".

I'm sure anyone capable of building it can add those bits if they want.


Lamb.h

Code: [Select]
#include <windows.h>


#ifndef _LAMB_
#define _LAMB_

#define sTYPE 0x45505954 // "TYPE"
#define sVER_ 0x20524556 // "VER "
#define sDESC 0x43534544 // "DESC"
#define sOWNR 0x524E574F // "OWNR"
#define sERA_ 0x20415245 // "ERA "
#define sERAX 0x54415245 // "ERAX"
#define sDIM_ 0x204D4944 // "DIM "
#define sUDTA 0x41544455 // "UDTA"
#define sUNIT 0x54494E55 // "UNIT"
#define sUGRD 0x44524755 // "UGRD"

#define sSIDE 0x45444953 // "SIDE"
#define sSGLD 0x444C4753 // "SGLD"
#define sSLBR 0x52424C53 // "SLBR"
#define sSOIL 0x4C494F53 // "SOIL"
#define sAIPL 0x4C504941 // "AIPL"

#define sMTXM 0x4D58544D // "MTXM"
#define sSQM_ 0x204D5153 // "SQM "
#define sOILM 0x4D4C494F // "OILM"
#define sREGM 0x4D474552 // "REGM"

#define sSIGN 0x4E474953 // "SIGN"
#define sALOW 0x574F4C41 // "ALOW"

#define FOREST     0
#define WINTER     1
#define WASTELAND  2
#define SWAMP      3


#define TILEW  32
#define TILEW2 16


extern "C" {
    typedef struct pudsect {
        DWORD Reserved;
        DWORD name;
        DWORD size;
        LPVOID data;
    }PUDSECT;
}

extern "C" {
    typedef struct hmibmp {
        BITMAPFILEHEADER* pFile;
        BITMAPINFOHEADER* pInfo;
        RGBQUAD*          pPal;
        BYTE*             pBits;
        int               width;
        int               height;
        int               bpp;
        int               linew;
        int               usage;
        int               size;
    }HMIBMP;
}

extern "C" {
    typedef struct pudunit{
    WORD x;
    WORD y;
    BYTE type;
    BYTE owner;
    WORD ai;     // 0-passive 1-active or (gold or oil)/2500
    }PUDUNIT;
}


// LambRES.dll
extern "C" typedef CHAR*   (__stdcall *rfngetname )(int utype);
extern "C" typedef LPVOID  (__stdcall *rfntileset )(int ntileset);
extern "C" typedef LPVOID  (__stdcall *rfngetpal  )(int npalette);
extern "C" typedef LPVOID  (__stdcall *rfngetgrp  )();


//PUDfile.inc
extern "C" typedef LPVOID  (__stdcall *pfnpudload )(CHAR* path);
extern "C" typedef int     (__stdcall *pfnpudsave )(LPVOID hpud,CHAR* path);

//PUDpud.inc
extern "C" typedef int     (__stdcall *pfnsectcnt )(LPVOID hpud);
extern "C" typedef void    (__stdcall *pfndestroy )(LPVOID hpud);
extern "C" typedef LPVOID  (__stdcall *pfndelsect )(LPVOID hpud,LPVOID hsect);
extern "C" typedef PUDSECT*(__stdcall *pfnfindsect)(LPVOID hpud,DWORD sectname);
extern "C" typedef int     (__stdcall *pfnupdsect )(LPVOID hpud,LPVOID hsect,LPVOID lpnew,int nbytes);
extern "C" typedef PUDSECT*(__stdcall *pfngetsect )(LPVOID hpud,int nsect);
extern "C" typedef int     (__stdcall *pfnsectndx )(LPVOID hpud,DWORD sectname);
extern "C" typedef LPVOID  (__stdcall *pfnsectset )(LPVOID hpud,LPVOID hsect,int nsect);
extern "C" typedef BOOL    (__stdcall *pfnsectcre )(LPVOID hpud,DWORD sectname,LPVOID lpnew,int nbytes);
extern "C" typedef LPVOID  (__stdcall *pfnrealloc )(PUDSECT* hSect,int nbytes);

//PUDunit.inc
extern "C" typedef int     (__stdcall *pfnunitsize)(int utype);
extern "C" typedef int     (__stdcall *pfnuniticof)(int utype);
extern "C" typedef int     (__stdcall *pfnlistget )(int list,int ndx);
extern "C" typedef int     (__stdcall *pfnlistnext)(int list,int utype);
extern "C" typedef int     (__stdcall *pfnlistprev)(int list,int utype);
extern "C" typedef LPVOID  (__stdcall *pfnlistname)(int list);

//PUDtile.inc
extern "C" typedef void    (__stdcall *pfnrndrmap )(LPVOID hbmp,LPVOID mtxm,int mapw);
extern "C" typedef void    (__stdcall *pfnrndrtile)(LPVOID hbmp,int tile,int x,int y);
extern "C" typedef LPVOID  (__stdcall *pfngettile )(int tile);
extern "C" typedef void    (__stdcall *pfntileset )(LPVOID tileset);
extern "C" typedef void    (__stdcall *pfnblack   )(HDC dc,int x,int y,int w,int h);

//hmibmp.inc
extern "C" typedef HMIBMP* (__stdcall *pfnmakebmp )(int w,int h,int bpp);
extern "C" typedef void    (__stdcall *pfnfreebmp )(HMIBMP* bmp);
extern "C" typedef int     (__stdcall *pfnzerobmp )(HMIBMP* bmp);
extern "C" typedef void    (__stdcall *pfnsavebmp )(CHAR* path,HMIBMP* bmp);
extern "C" typedef void    (__stdcall *pfnsavejpg )(CHAR* path,HMIBMP* bmp,int quality);
extern "C" typedef void    (__stdcall *pfnperfbmp )(HMIBMP* bmp);
extern "C" typedef void    (__stdcall *pfncopyimg )(HMIBMP* src,int scrx,int srcy,int srcw,int scrh,HMIBMP* dst,int dstx,int dsty,int transp);
extern "C" typedef int     (__stdcall *pfncopyfull)(HMIBMP* dstbmp,HMIBMP* srcbmp,int transp);
extern "C" typedef void    (__stdcall *pfndispimg )(HDC destDC,int x,int y,int w,int h,HMIBMP* bmp,int dx,int dy,int dw,int dh);
extern "C" typedef void    (__stdcall *pfnsetpal  )(HMIBMP* bmp,LPVOID palette);
extern "C" typedef void    (__stdcall *pfndrawrect)(HMIBMP* bmp,int x,int y,int w,int h,int color);
extern "C" typedef HMIBMP* (__stdcall *pfnsizebmp )(HMIBMP* bmp,int w,int h);

//PUDgrp.inc
extern "C" typedef LPVOID  (__stdcall *pfngrpinit )(LPVOID grplubase);
extern "C" typedef void    (__stdcall *pfndrawgrp )(int grp,int nframe,LPVOID daddr,int dwidth,int owner,int centre,int mirror);
extern "C" typedef void    (__stdcall *pfndrawbtn )(LPVOID bmp, int xpos, int ypos, int icon, int state);




extern rfngetname      RESgetName;
extern rfntileset      RESgetTileset;
extern rfngetpal       RESgetPalette;
extern rfngetgrp       RESgetGrp;

extern pfnpudload      PUDload;
extern pfnpudsave      PUDsave;

extern pfnsectcnt      PUDsection_count;
extern pfndestroy      PUDdestroy;
extern pfndelsect      PUDdelete_section;
extern pfnfindsect     PUDfind_section;
extern pfnupdsect      PUDupdate_section;
extern pfngetsect      PUDget_section;
extern pfnsectndx      PUDsection_index;
extern pfnsectset      PUDsection_set_index;
extern pfnsectcre      PUDcreate_section;
extern pfnrealloc      PUDsection_realloc;

extern pfnunitsize     PUDunitSize;
extern pfnuniticof     PUDunitIconFrame;
extern pfnlistget      PUDlistGet;
extern pfnlistnext     PUDlistNext;
extern pfnlistprev     PUDlistPrev;
extern pfnlistname     PUDlistName;

extern pfnrndrmap      PUDrenderMap;
extern pfnrndrtile     PUDrenderTile;
extern pfngettile      PUDgetTile;
extern pfntileset      PUDtileset;
extern pfnblack        PUDblack;

extern pfnmakebmp      make_bitmap;
extern pfnfreebmp      free_bitmap;
extern pfnzerobmp      zero_bitmap;
extern pfnsavebmp      save_bitmap;
extern pfnsavejpg      save_jpeg;
extern pfnperfbmp      perforate_bitmap;
extern pfncopyimg      copy_image;
extern pfncopyfull     copy_full_image;
extern pfndispimg      display_image;
extern pfnsetpal       set_palette;
extern pfndrawrect     draw_rect;
extern pfnsizebmp      size_bitmap;

extern pfngrpinit      GRPinit;
extern pfndrawgrp      GRPdraw;
extern pfndrawbtn      GRPdrawButton;


#endif


PUDPIC.cpp
Code: [Select]
#include <windows.h>
#include <lamb.h>


HMODULE hResDll  = LoadLibraryA("LambRES");
HMODULE hLambDll = LoadLibraryA("LambWC2");


rfngetpal   RESgetPalette       = (rfngetpal  )GetProcAddress(hResDll , "RESgetPalette"       );
rfngetgrp   RESgetGrp           = (rfngetgrp  )GetProcAddress(hResDll , "RESgetGrp"           );
rfngetname  RESgetName          = (rfngetname )GetProcAddress(hResDll , "RESgetName"          );
rfntileset  RESgetTileset       = (rfntileset )GetProcAddress(hResDll , "RESgetTileset"       );


pfnpudload  PUDload             = (pfnpudload )GetProcAddress(hLambDll, "PUDload"             );
pfnpudsave  PUDsave             = (pfnpudsave )GetProcAddress(hLambDll, "PUDsave"             );

pfnsectcnt  PUDsection_count    = (pfnsectcnt )GetProcAddress(hLambDll, "PUDsection_count"    );
pfndestroy  PUDdestroy          = (pfndestroy )GetProcAddress(hLambDll, "PUDdestroy"          );
pfndelsect  PUDdelete_section   = (pfndelsect )GetProcAddress(hLambDll, "PUDdelete_section"   );
pfnfindsect PUDfind_section     = (pfnfindsect)GetProcAddress(hLambDll, "PUDfind_section"     );
pfnupdsect  PUDupdate_section   = (pfnupdsect )GetProcAddress(hLambDll, "PUDupdate_section"   );
pfngetsect  PUDget_section      = (pfngetsect )GetProcAddress(hLambDll, "PUDget_section"      );
pfnsectndx  PUDsection_index    = (pfnsectndx )GetProcAddress(hLambDll, "PUDsection_index"    );
pfnsectset  PUDsection_set_index= (pfnsectset )GetProcAddress(hLambDll, "PUDsection_set_index");
pfnsectcre  PUDcreate_section   = (pfnsectcre )GetProcAddress(hLambDll, "PUDcreate_section"   );
pfnrealloc  PUDsection_realloc  = (pfnrealloc )GetProcAddress(hLambDll, "PUDsection_realloc"   );


pfnunitsize PUDunitSize         = (pfnunitsize)GetProcAddress(hLambDll, "PUDunitSize"         );
pfnuniticof PUDunitIconFrame    = (pfnuniticof)GetProcAddress(hLambDll, "PUDunitIconFrame"    );
pfnlistget  PUDlistGet          = (pfnlistget )GetProcAddress(hLambDll, "PUDlistGet"          );
pfnlistnext PUDlistNext         = (pfnlistnext)GetProcAddress(hLambDll, "PUDlistNext"         );
pfnlistprev PUDlistPrev         = (pfnlistprev)GetProcAddress(hLambDll, "PUDlistPrev"         );
pfnlistname PUDlistName         = (pfnlistname)GetProcAddress(hLambDll, "PUDlistName"         );

pfnrndrmap  PUDrenderMap        = (pfnrndrmap )GetProcAddress(hLambDll, "PUDrenderMap"        );
pfnrndrtile PUDrenderTile       = (pfnrndrtile)GetProcAddress(hLambDll, "PUDrenderTile"       );
pfngettile  PUDgetTile          = (pfngettile )GetProcAddress(hLambDll, "PUDgetTile"          );
pfntileset  PUDtileset          = (pfntileset )GetProcAddress(hLambDll, "PUDtileset"          );
pfnblack    PUDblack            = (pfnblack   )GetProcAddress(hLambDll, "PUDblack"            );

pfnmakebmp  make_bitmap         = (pfnmakebmp )GetProcAddress(hLambDll, "make_bitmap"         );
pfnfreebmp  free_bitmap         = (pfnfreebmp )GetProcAddress(hLambDll, "free_bitmap"         );
pfnzerobmp  zero_bitmap         = (pfnzerobmp )GetProcAddress(hLambDll, "zero_bitmap"         );
pfnsavebmp  save_bitmap         = (pfnsavebmp )GetProcAddress(hLambDll, "save_bitmap"         );
pfnsavejpg  save_jpeg           = (pfnsavejpg )GetProcAddress(hLambDll, "save_jpeg"           );
pfnsizebmp  size_bitmap         = (pfnsizebmp )GetProcAddress(hLambDll, "size_bitmap"         );
pfnperfbmp  perforate_bitmap    = (pfnperfbmp )GetProcAddress(hLambDll, "perforate_bitmap"    );
pfncopyimg  copy_image          = (pfncopyimg )GetProcAddress(hLambDll, "copy_image"          );
pfncopyfull copy_full_image     = (pfncopyfull)GetProcAddress(hLambDll, "copy_full_image"     );
pfndispimg  display_image       = (pfndispimg )GetProcAddress(hLambDll, "display_td_image"    );
pfnsetpal   set_palette         = (pfnsetpal  )GetProcAddress(hLambDll, "set_palette"         );
pfndrawrect draw_rect           = (pfndrawrect)GetProcAddress(hLambDll, "draw_rect"           );

pfngrpinit  GRPinit             = (pfngrpinit )GetProcAddress(hLambDll, "GRPinit"             );
pfndrawgrp  GRPdraw             = (pfndrawgrp )GetProcAddress(hLambDll, "GRPdraw"             );
pfndrawbtn  GRPdrawButton       = (pfndrawbtn )GetProcAddress(hLambDll, "GRPdrawButton"       );


CHAR* pudpath = "this.pud";
CHAR* bmppath = "this.bmp";
CHAR* jpgpath = "this.jpg";

BYTE* sectionData(LPVOID hpud, DWORD sname){
    PUDSECT* sptr = PUDfind_section(hpud,sname);
    if (sptr!=NULL) return (BYTE*)sptr->data;
    return NULL;
}

int sectionSize(LPVOID hpud, DWORD sname){
    PUDSECT* sptr = PUDfind_section(hpud,sname);
    if (sptr!=NULL) return sptr->size;
    return 0;
}

int getPudSize(LPVOID hpud){
    WORD* pdim = (WORD*) sectionData(hpud,sDIM_);
    if(pdim) return (int) *pdim;
    return 0;
}

int getTerrainType(LPVOID hpud){
    WORD* pter = (WORD*) sectionData(hpud,sERA_);
    if(pter) return (int) *pter;
    return 0;
}

BOOL isBuilding(int utype){
    // is the unit a building?
    return utype>=0x3A;
}

void renderUnit(HMIBMP* hbm, PUDUNIT* unit){
    // draw a unit grp
   
    int   frame = 0;
    int   x=(unit->x+1)*TILEW;
    int   y=(unit->y+1)*TILEW;
    int   centre = 0;
    int   rev = 0;
   
   
    if(!isBuilding(unit->type)){
       // units need to be centred and offset
       centre = 1;
       x+=TILEW2;
       y+=TILEW2;
       
       // pick a random direction so they dont all face the same way
       frame = rand()%5;
       rev   = rand()%2;    // draw reversed?
    }
   
    GRPdraw( unit->type, frame, hbm->pBits+x+(y*hbm->linew), hbm->linew, unit->owner, centre, rev );

}


///////// START /////////


    // load the pud file
    LPVOID hPud = PUDload(pudpath);
   
   
    // get some info from the pud
    int mapsize = getPudSize(hPud);
    int terrain = getTerrainType(hPud);
   

    // make a bitmap in memory (tiles are 32x32 pixels)
    HMIBMP* hbm = make_bitmap(mapsize*TILEW,mapsize*TILEW,8);
   
   
   
    /// TERRAIN ///
   
    // use the tiles for the map terrain type
    PUDtileset(RESgetTileset(terrain));
   
    // don't forget this if you are using GRPs, only needs to be done once to initialize
    GRPinit(RESgetGrp());
   
    //paste all the tile graphics for the pud onto the bitmap
    PUDrenderMap( hbm, sectionData(hPud,sMTXM) , mapsize);
   
       
    /// UNITS ///
           
    // get a pointer to the "UNIT" section
    PUDSECT* units = PUDfind_section(hPud,sUNIT);
       
    if(units){
         
        // make a slightly larger bitmap to paste units on
        // --> some units like flyers can be placed in locations where they
        //     will render off the edge of the map (crash and burn).
        //
        // so here we make a bitmap with a safety margin around the edge
       
        HMIBMP* hUbm = make_bitmap((mapsize+2)*TILEW,(mapsize+2)*TILEW,8);
             
        // how many units on the pud?
        // ( includes mines, start locations etc.)
        int nUnits  = units->size/sizeof(PUDUNIT);
       
        // draw the unit GRPs on the 'safe' bitmap
        PUDUNIT* pUnit = (PUDUNIT*)units->data;
        for(int i=0;i<nUnits;i++){
            renderUnit(hUbm,pUnit);
            pUnit++;
        }
       
        // copy the unit bitmap (less the border area) onto the terrain bitmap
        copy_image(hUbm,TILEW,TILEW,hbm->width,hbm->height,hbm,0,0,0); // <- last 0 is the transparent index
                                                                       //    pass -1 for none.
        // dispose of the unit bitmap
        free_bitmap(hUbm);
    }
   
   
    // ensure the bmp file has the correct palette for the terrain type
    set_palette(hbm , RESgetPalette( terrain ));
   
    // save the full bitmap to a .bmp file
    save_bitmap(bmppath,hbm);
   
    // resize the bitmap then save to a .jpg file
    HMIBMP* hJbm = size_bitmap(hbm,1024,1024);
    save_jpeg(jpgpath,hJbm,90); // <-- quality 90 looks nice
   
    // dispose of bitmaps
    free_bitmap(hbm);
    free_bitmap(hJbm);
   
    // dispose of the pud structure
    PUDdestroy(hPud);


                                                            :critter:

Title: Re: Nerd's Corner
Post by: Cel on October 14, 2018, 12:40:20 AM
Nice thanks! ^-^ :thumbsup:

Interesting that they save the transition type value from the marching squares algorithm in the pud directly instead of calculating it once at load time. It means your map editor has to save these calculated values in the pud but it also means you can save a pud files with very weird transitions if you would like to that could look funny. (:

 :critter:
Title: Re: Nerd's Corner
Post by: Lambchops on October 14, 2018, 07:42:34 AM
Nice thanks! ^-^ :thumbsup:

Interesting that they save the transition type value from the marching squares algorithm in the pud directly instead of calculating it once at load time. It means your map editor has to save these calculated values in the pud but it also means you can save a pud files with very weird transitions if you would like to that could look funny. (:

 :critter:



yw :)

The terrain transition tile values can be derived like THIS (http://forum.war2.ru/index.php/topic,2703.msg63798.html#msg63798).

For displaying terrain in the PUDPIC program I cheated - big time ;)

I generated a list of possible MTXM values based on my assumptions of the format, then also searched every pud in my maps directory for any crazy custom values I had missed and added them too.

Then I auto generated maps with arrays of these MTXM values, then loaded the maps, took SS, and then processed the SS to pull out the exact 32x32 block of pixels for each map value.


 ... stuff like this:



(http://forum.war2.ru/index.php?action=dlattach;topic=2703.0;attach=2677)


Finally I searched all the pixel blocks and weeded out any repeats, then turned them into an array of pixel data indexed by the MTXM value list - with multiple indexes to the same pixels for different tile values that displayed them.

In this way when rendering there is no need to calculate and locate the 4 different 8x8 mini-tiles that make up each MTXM location, it just uses the raw MTXM value to do a lookup in a pointertable  which supplies the exact location of the full 32x32 block.

                                                                                :critter:


 -- edit --

The units are all rendered using the original grp files, using the method detailed HERE (http://forum.war2.ru/index.php?action=dlattach;topic=2703.0;attach=1091)


Title: Re: Nerd's Corner
Post by: Lambchops on October 22, 2018, 11:43:31 AM
u are invited to my xmas party

Thanks @easycompany - as soon as my fairy godmother buys me a plane ticket and pays for me to get a passport, I'll be there with bells on ...

  ... so probably never lol, but it's a nice thought - I'd be happy to help you drink some beers. Maybe one day.
Title: Re: Nerd's Corner
Post by: Lambchops on January 23, 2019, 11:28:04 PM
BNETD Source (https://www.cs.cmu.edu/~dst/DMCA/BNETD/bnetd-0.4.25/src/)


Title: Re: Nerd's Corner
Post by: Lambchops on February 27, 2019, 09:52:21 PM
Font .fnt format here (http://forum.war2.ru/index.php/topic,4701.msg76149.html#msg76149)
Title: Re: Nerd's Corner
Post by: Lambchops on March 01, 2019, 06:52:19 AM
Source code for War2FontTool.exe (description) (http://forum.war2.ru/index.php/topic,4701.msg76189.html#msg76189)
Code: [Select]
// Warcraft II font Extractor/Compiler
// Lambchops Feb 2019

#include <windows.h>
#include <shlwapi.h>

#define INVALID_FILE  1
#define INVALID_INPUT 2
#define READ_ERROR    3
#define WRITE_ERROR   4
#define ALLOC_FAIL    5

#define BG_COLOR 0x18
#define MAX_CHAR_SIZE 4108


typedef struct   _FontHeader {
   DWORD  FourCC;              //   Always "FONT"
   BYTE   LowIndex;            //   Index of first letter in file
   BYTE   HighIndex;           //   Index of the last letter in file
   BYTE   MaxWidth;            //   Maximum width
   BYTE   MaxHeight;           //   Maximum height
} FontHeader;

typedef struct  _FontLetterRaw {
   BYTE   Width;     //   Width of the letter
   BYTE   Height;    //   Height of the letter
   BYTE   XOffset;   //   X Offset for the topleft corner of the letter.
   BYTE   YOffset;   //   Y Offset for the topleft corner of the letter.
} FontLetterRaw;

BYTE clrndx[ ] = {BG_COLOR,0xC8,0xC7,0x4A,0xC0,0x00};

char f_ext[] = "fnt";
char b_ext[] = "bmp";
char szBmpTmpl[] = "_%3.3d.bmp";
char szFntTmpl[] = ".fnt";
char szFont4cc[] = "FONT";
char pathbuf[512];
char szHelpText[]   = "  Warcraft II Font Extractor/Compiler - Lambchops Feb 2019\r\rDrop a .fnt file to extract.\rDrop one of the extracted .bmp files to compile.\r\r *Make sure you only use the existing colors when editing\r  unknown colors will be deleted.";


// --- FILE/PATH --- //

int get_flen(CHAR* path){
    HANDLE fn = CreateFile(path,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
    int r = GetFileSize(fn,NULL);
    CloseHandle(fn);
    return r;
}

CHAR* filename(CHAR* lppath){
CHAR* r = lppath+lstrlen(lppath);
while(r>lppath){
if(*r==0x5C)return (r+1);
r--;
}
return lppath;
}

CHAR* get_extension(CHAR* lppath){
CHAR* r = lppath+lstrlen(lppath);
CHAR* def = r;
while(r>lppath){
if(*r==0x2E)return (r+1);
r--;
}
return def;
}

int loadlen;

HANDLE bload(char* path){
    // Allocate global memory and read in a file
    HANDLE fn = CreateFile(path,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
    DWORD nb;
    HANDLE fdat;

    if(fn!=INVALID_HANDLE_VALUE){
        loadlen = GetFileSize(fn,NULL);

        // allocate a buffer
        fdat = GlobalAlloc(GPTR,loadlen);

        // read file into buffer
        ReadFile(fn,fdat, loadlen, &nb, NULL);
        CloseHandle(fn);

       if(nb==loadlen)return fdat;             
       GlobalFree(fdat);
    }
    return NULL;
}



// --- BITMAP --- //

int bmp8len = 0x1436;
DWORD bmp8[] = {0x14364D42,0,0x04360000,0x00280000,0x00400000,0x00400000,0x00010000,0x00000008,0x10000000,0,0,0,0,0,0x94FC0000,
0xD0000000,0xFF0000FC,0x00FC0000,0x00FC0000,0x00FC0000,0x00FC0000,0x00FC0000,0x00FC0000,0x28280000,0x00FC00CC,0xFC480000,0xCC2800FC,0xA01000E4,0x740000CC,0x240000B4,0x2C000000,
0x34000000,0x40040014,0x4804000C,0x540C0024,0x5C100028,0x6414002C,0x6C1C003C,0x7828004C,0x8030005C,0x8C3C006C,0x4C000080,0x20540000,0x285C0000,0x2C640000,0x30680000,0x34700000,
0x38740004,0x44780004,0x50800008,0x5C880010,0x487C0018,0x4C80000C,0x4880000C,0x447C000C,0x40780008,0x38740008,0x38740004,0x38740004,0x38740004,0x40780004,0x50840008,0x5C8C0010,
0x6C940018,0x608C0024,0x5888001C,0x50840014,0x20040010,0x2808003C,0x34100048,0x042C0058,0x042C00FC,0x540000FC,0x60040000,0x70340010,0x7C1C003C,0xA038004C,0x04040080,0x10100004,
0x18180010,0x24240018,0x30300024,0x3C3C0030,0x4848003C,0x50500048,0x5C5C0050,0x6868005C,0x74740068,0x7C7C0074,0x8888007C,0x94940088,0xA0A00094,0xACAC00A0,0x440000AC,0x14000000,
0x1C000018,0x20000024,0x2C000030,0x30000040,0x38000050,0x40000060,0x4404006C,0x4C000074,0x54080078,0x6018007C,0x6C280088,0x7C3C0090,0x844C0098,0x3C0000A0,0x14140000,0x1C1C0014,
0x2828001C,0x34340028,0x40400034,0x4C4C0040,0x5858004C,0x64640058,0x6C6C0064,0x7878006C,0x84840078,0x90900084,0x9C9C0090,0xA8A8009C,0xB4B400A8,0xC0C000B4,0xCCCC00C0,0xD8D800CC,
0x343400D8,0x44400044,0x54500054,0x64600068,0x78700078,0x8880008C,0x9C90009C,0xB0A400B0,0xC4B400C0,0x485800D4,0x5C6C0030,0x74800044,0x8C94005C,0x9CA4007C,0x14000090,0x18000024,
0x2000002C,0x24040034,0x2C04003C,0x30080048,0x380C0050,0x40140058,0x4C180064,0x581C006C,0x60240078,0x6C280080,0x7830008C,0x84380094,0x944000A0,0xA04800A8,0x340000B4,0x40000018,
0x4C00001C,0x58000024,0x64040028,0x70040030,0x80080034,0x8810003C,0x9414004C,0xA018005C,0xAC20006C,0xB828007C,0x34140090,0x48140074,0x6418009C,0x841400C4,0x000000F0,0x00000018,
0x0000002C,0x00000044,0x0000005C,0x00000074,0x00000088,0x000000A0,0x000000B8,0x381000D0,0x4C1C0060,0x64280074,0x7C3C0088,0x9054009C,0xA87400B4,0xC49800CC,0x002400E8,0x00300000,
0x04400000,0x0C4C0000,0x185C0000,0x28700000,0x34780000,0x40840004,0x5090000C,0x60980018,0x70A40024,0x80B00034,0xF4580044,0xB43800FC,0x601800FC,0x000000FC,0x300000FC,0x4000005C,
0x50040068,0x64080078,0x780C0088,0x8C100098,0xA41400A8,0xC01C00BC,0xE02000D0,0x000000F4,0x000000FC,0x94FC00B0,0xD0000000,0x000000FC,0x00FC00FC,0xFC000000,0,0x000000A4,
0x0400007C,0x0400005C,0x48CC0044,0x28A0000C,0x14740004,0x044C0000,0xB4940000,0x845C002C,0x542C0014,0x280C0004,0x48B00000,0x2C840098,0x18580074,0x082C0050,0x8C14002C,0x601000F8,
0x3C1000C8,0x200C0098,0x283C006C,0x1C2C0028,0x1420001C,0x0C140014,0xE0E0000C,0x98B400E0,0x54800098,0x284C0054,0x40140024,0x58200068,0x7030007C,0x00000090,0x5CA00000,0x34780018,
0x50840004,0x6C8C0010,0x80E40018,0x8448001C,0xF8F000A8,0xA0A400FC,0x808000A0,0x00000080,0xFC0000FC,0xFC000000,0x00FC00FC,0x00FC0000,0xFCFC00FC,0xFCFC0000,0x000000FC,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

BYTE* bmptr = (BYTE*)bmp8;
BYTE* pixmap;
int linew,bmw,bmh;

void init_bmp(int w,int h){
    // initialize the bitmap buffer for the supplied size
   
    BITMAPFILEHEADER* bfh = (BITMAPFILEHEADER*)bmptr;
    BITMAPINFOHEADER* bih = (BITMAPINFOHEADER*)(bmptr+sizeof(BITMAPFILEHEADER));
                   pixmap = bmptr+bfh->bfOffBits;
                    linew = ((w+3)>>2)<<2;
    int             psize = linew*h;
   
    bfh->bfSize  = bfh->bfOffBits+psize;
    bih->biWidth = w;
    bih->biHeight= h;
    bmw = bih->biWidth;
    bmh = bih->biHeight;
    FillMemory(pixmap,psize,BG_COLOR);
}



void set_pixel(int x,int y,int c){
    // set a pixel in the current bitmap
    BYTE* pptr = pixmap+(linew*(bmh-y-1))+x;
    *pptr = c;
}

int get_pixel(int x,int y){
    // get a pixel from the current bitmap
    BYTE* pptr = pixmap+(linew*(bmh-y-1))+x;
    return *pptr;
}

void normalize_bmp(){
    // change palette indexes to font indexes     
    //  change unknown values to transparent

    int c;
    for(int y=0;y<bmh;y++){
        for(int x=0;x<bmw;x++){
            c = get_pixel(x,y);
            set_pixel(x,y,0);
            for(int i=0;i<=5;i++){
                if(c==clrndx[i]){
                    set_pixel(x,y,i);
                    break;
                }
            }
        }
    }
}

int bmp_yos(){
    // find non-zero Y offset
    for(int y=0;y<bmh;y++){
        for(int x=0;x<bmw;x++){
            if(get_pixel(x,y)!=0)return y;
        }
    }
    return -1;
}

int bmp_xos(){
    // find non-zero X offset
    for(int x=0;x<bmw;x++){   
        for(int y=0;y<bmh;y++){
            if(get_pixel(x,y)!=0)return x;
        }
    }
    return -1;
}

BOOL save_bmp(char* path){
    // save the current bitmap
    BITMAPFILEHEADER* bfh = (BITMAPFILEHEADER*)bmptr;   
    HANDLE fn = CreateFile(path,GENERIC_WRITE,FILE_SHARE_WRITE,0,CREATE_ALWAYS,0,0);
    DWORD nb;
   
    if(fn!=INVALID_HANDLE_VALUE){
        if(WriteFile(fn,bmptr,bfh->bfSize,&nb,NULL)){
            CloseHandle(fn);
            return TRUE;
        }
        CloseHandle(fn);
    }
    return FALSE;
}



BOOL load_bmp(char* path){
    BITMAPFILEHEADER* bfh = (BITMAPFILEHEADER*)bmptr;
    BITMAPINFOHEADER* bih = (BITMAPINFOHEADER*)(bmptr+sizeof(BITMAPFILEHEADER));
    HANDLE fn = CreateFile(path,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
    DWORD nb;

    if(fn!=INVALID_HANDLE_VALUE){
        loadlen = GetFileSize(fn,NULL);

        // read file into buffer
        ReadFile(fn,bmp8, loadlen, &nb, NULL);
        CloseHandle(fn);

       if(nb==loadlen){
           bmw    = bih->biWidth;
           bmh    = bih->biHeight;
           pixmap = bmptr+bfh->bfOffBits;
           linew  = ((bmw+3)>>2)<<2;
             
           return TRUE;
       }
    }
    return FALSE;   
}

BITMAPINFOHEADER* bmp_info(){
    return (BITMAPINFOHEADER*)(bmptr+sizeof(BITMAPFILEHEADER));               
}

// --- EXTRACT --- //


BOOL extract_char(HANDLE hFont,int base,int c,char* path){
    FontLetterRaw* flr;
    BYTE*  bptr = (BYTE*)hFont;
    DWORD* dptr = (DWORD*)hFont;
    int    px = 0;
    int    py = 0;

    // get file offset   
    dptr += (c-base+2);
    if(!(*dptr))return FALSE;
    bptr +=(*dptr);
   
    // read character header
    flr   =(FontLetterRaw*)bptr;
    bptr += sizeof(FontLetterRaw);
   
    // initialize output bitmap
    init_bmp( flr->Width+flr->XOffset, flr->Height+flr->YOffset );
   
    // set pixels
    while(py<flr->Height){
               
        // read data byte
        c = *bptr;       
        bptr++;
       
        // apply shift
        px+=(c>>3);
        c&=7;
       
        // wrap
        while(px>=flr->Width){
            px -= flr->Width;
            py++;
        }
       
        // set pixel
        if(c&&py<flr->Height){
            set_pixel( px+flr->XOffset, py+flr->YOffset, clrndx[c] );   
            px++;
        }
    }
    save_bmp(path);
}

BOOL test4cc(char* a,char* b){
    for(int i=0;i<4;i++){
        if(*a!=*b)return FALSE;       
        a++;
        b++;
    }
    return TRUE;
}

int do_extract(char* path){
    FontHeader* fh;
    char* bpath;
    HANDLE hFont = bload(path);
       
    if(hFont!=NULL){
        // verify 4CC
        if(test4cc((char*)szFont4cc,(char*)hFont)){
           
            // prepare output path
            lstrcpy(pathbuf,path);
            bpath = get_extension(pathbuf)-1;
                                                   

            // read the file header
            fh = (FontHeader*)hFont;
           
            // process the characters
            for(int c=fh->LowIndex;c<=fh->HighIndex;c++){
                // make bmp filename
                wsprintf(bpath,szBmpTmpl,c);
                // extract the character
                extract_char(hFont,fh->LowIndex,c,pathbuf);
            }
           
            GlobalFree(hFont);   
            return EXIT_SUCCESS;

        }
        GlobalFree(hFont);
        return INVALID_FILE;

    }
    return READ_ERROR;
}


// --- COMPILE --- //

int compile_char(BYTE* optr){
    // write raw data for current bmp char at optr
    // return data size in bytes
   
    int c,t;
    FontLetterRaw* flr = (FontLetterRaw*)optr;
    optr+=sizeof(FontLetterRaw);   
   
    // set character header
    int yos = bmp_yos();
    if(yos==-1)return 0;
    flr->YOffset = yos;
    flr->XOffset = bmp_xos();
    flr->Width   = bmw-flr->XOffset;
    flr->Height  = bmh-flr->YOffset;
   
    // compile pixels
    t=0;
    for(int y=flr->YOffset;y<bmh;y++){
        for(int x=flr->XOffset;x<bmw;x++){
            c=get_pixel(x,y);
            if(c){
                *optr=(t<<3)+c;
                t=0;
                optr++;
            }else{
                t++;
                if(t==31){
                    *optr=0xF8;
                    optr++;
                    t=0;
                }
            }
        }
    }
    if(t){
        *optr=(t<<3);
        optr++;             
    }
   
    return (int)optr-(int)flr;
}


int do_compile(CHAR* path){
    HANDLE fn;
    DWORD nb;
    int len;
    BITMAPINFOHEADER* bih;
    FontHeader* fh;
    BYTE* hFont;
    char* bpath;
    DWORD* fptr;
    BYTE* optr;
    int datsize;
    int maxw = 0;
    int maxh = 0;
    int minc = 0x20;
    int maxc = 0;
    int nchar= 0;
   
    // enum char bitmaps
    lstrcpy(pathbuf,path);
    bpath = get_extension(pathbuf)-5;

    for(int i=1;i<256;i++){
        wsprintf(bpath,szBmpTmpl,i);
        if(PathFileExists(pathbuf)){       
            if(get_flen(pathbuf)<=bmp8len){
                if(i<minc)minc=i;
                if(i>maxc)maxc=i;
                load_bmp(pathbuf);
                bih = bmp_info();
                if(bih->biWidth>maxw)maxw=bih->biWidth;
                if(bih->biHeight>maxh)maxh=bih->biHeight;
            }                   
        }
    }
       
    if(!maxw*maxh*maxc)return INVALID_INPUT;
    if(maxc<minc){ minc=maxc; maxc=0x20; }
    nchar = maxc-minc+1;
   
    // allocate output buffer
    hFont = (BYTE*)GlobalAlloc(GPTR,nchar*MAX_CHAR_SIZE);
    if(!hFont)return ALLOC_FAIL;
   
    // set up pointers
    fh=(FontHeader*)hFont;
    fptr=(DWORD*)(hFont+sizeof(FontHeader));
    optr=(BYTE*)(hFont+sizeof(FontHeader)+nchar*4);
   
    // write font header
    lstrcpy((char*)hFont,szFont4cc);
    fh->LowIndex  = minc;
    fh->HighIndex = maxc;
    fh->MaxWidth  = maxw;
    fh->MaxHeight = maxh;
   
    // compile characters
    for(int c=minc;c<=maxc;c++){
        datsize = 0;
        wsprintf(bpath,szBmpTmpl,c);
        if(PathFileExists(pathbuf)){
            len = get_flen(pathbuf);
            if(len&&len<=bmp8len){
                if(!load_bmp(pathbuf)){
                    GlobalFree(hFont);
                    return READ_ERROR;
                }
                normalize_bmp();
                datsize = compile_char(optr);
            }
        }
        // write file offset
        if(datsize)*fptr=optr-hFont;
        fptr++;
        optr+=datsize;
    }
   
    // write fnt file
   
    datsize=optr-hFont;
    lstrcpy(bpath,szFntTmpl);
    fn = CreateFile(pathbuf,GENERIC_WRITE,FILE_SHARE_WRITE,0,CREATE_ALWAYS,0,0);
   
    if(fn==INVALID_HANDLE_VALUE){
        GlobalFree(hFont);
        return WRITE_ERROR;
    }else{
        if(WriteFile(fn,hFont,datsize,&nb,NULL)){
            CloseHandle(fn);
            GlobalFree(hFont);
            if(nb==datsize)return 0;
            return WRITE_ERROR;
        }
        CloseHandle(fn);
        GlobalFree(hFont);
        return WRITE_ERROR;
    }
}


// --- HELP --- //

int do_help(){
    MessageBox(0,szHelpText,"War2 Font Tool",0);
    return EXIT_SUCCESS;
}
// --- MAIN --- //


int main(int argc, char *argv[]){
    CHAR* e;
    if(lstrlen(argv[1])>3){
        e=get_extension(argv[1]);
        if(lstrlen(e)!=3)return INVALID_FILE;
        if(!lstrcmpi(e,f_ext))return do_extract(argv[1]);
        if(!lstrcmpi(e,b_ext))return do_compile(argv[1]);
    }else{
        return do_help();
    }
}
Title: Re: Nerd's Corner
Post by: Lambchops on March 29, 2019, 06:55:54 AM
                 HOSTING INTERFACE



NOTE: This project has been repurposed as the WC2 Plugin Framework (BELOW)




The hosting / port forwarding / firewall hole punching thing has been an issue since BNE came out.

I started on a fix for this last year, however my current work commitments mean that I am unlikely to find the time to finish this in the forseeable future.

I have completed what is probably the trickiest part of the project which is to provide an interface between the appropriate parts of the wc2 process and an external program, so I have decided to release this in the hope that someone else can put the time into developing and testing the rest of it.



---------------------------------------------------


So how does this work?

If you copy the included PE files into an existing BNE installation you should find that when you join a game you will get a message on the screen saying "JOINING" then the game name, and likewise when you create a game you will get a message saying "HOSTING" then the game name.

If you look at the host.dll source code you will see where these messages are being generated.



The host.dll module is required to export 3 functions called "w2p_init", "create_game" and "join_game".


>  w2p_init has no arguments and is called when the exe is first started. Any initialization code should go here.

>  create_game will be passed a pointer to the game name and called when the player creates a game.

>  join_game will be passed a pointer to the game name and called when the player joins a game.


----------------------------------------


So what needs to be done with this to fix the hosting problem?


There's a bit of work to do yet, but its all bread & butter networking stuff so I'm hoping there are people in the community that can do the job....

You will need to make a custom server, and your own "host.dll" that exports those 3 functions. The example source is in C++, however any language capable of building a normal windows dll can be used.

w2p_init() will just have whatever initialization code is required to support the rest of the project. Possibly a TCP connection to the hosting server could be started here, but personally I think this would be more reliable being done on a game-by-game basis.

join_game() should be fairly simple, it just needs to send a message (probably over TCP) to the server saying "im trying to join this game" with the player's name, the game name, and the client's game port, the terminate the connection. Probably the server should be able to find the ip address from the incoming message, or possibly the client will have to obtain its own external address and supply it as part of the message.

create_game() when hosting, the client will need to negotiate a TCP connection with the server and supply the name of the game it is hosting, then start a thread that listens to that connection for messages from the server. It should get a message from the server over the TCP connection when a player is trying to join with the IP address and game port of the joining client. When this message is received it will need to ping the joining cllient with appropriate UDP packets to facillitate the hole-punching. Finally it will need to notify the server when the game is starting then terminate the listening thread.

The Server:

The server will need to listen for and accept incoming TCP connection from clients, and maintain a list of the active hosting connections.

When a client notifies that it is hosting a game, the game name should be stored in the list.

When a hosting client notifies that the game has started, terminate the connection and remove the game from the list.

When a client notifies that it is joining a game, look up the game name in the list, then notify the hosting client of the joining clients IP address and game port.

Joining clients are not required to be stored in the list for basic functionality, however it might be a god idea to store the info for a short amount of time to protect against faulty clients or DDOS etc.


    --------------------------


There will no doubt be lots of lots of dev and testing required, but I think it is quite achievable. I am very happy to offer whatever technical support I can, but I simply don't have the time right now to develop the whole thing on my own.


one, two, three ..... GO!   

                                                     :critter:


Title: Re: Nerd's Corner
Post by: fois on March 29, 2019, 04:19:07 PM
Interesting... I had a whole different idea, my plan was to create a wsock32 proxy that works with any version of the game (without any kind of game patches).

I wanted to catch the packet that's being sent when you try to join a room, take it and append a id (a crc32 of the host's name possibly) and forward it to a server. The server will now forward the packet to the host (It knows where to send it, it reads the id) and appends the IP/Port of the sender. The host will now receive the packet from the server containing the original senders IP/Port, he will now send a packet to the original sender and that's pretty much it, holepunching is done :)

For this to work I would've created another thread that keeps sending a keep alive packet each 30seconds or so to the server, this is where the players announce their ids. The server will save the id/ip+port combo and store it, this way it always knows where to forward the packets when someone tries to join a game.

This is supposed to be a fully UDP solution, no changes or any kind of interaction with the pvpgn server are required.
Title: Re: Nerd's Corner
Post by: Lambchops on March 30, 2019, 07:26:36 AM
Interesting... I had a whole different idea, my plan was to create a wsock32 proxy that works with any version of the game (without any kind of game patches).

I wanted to catch the packet that's being sent when you try to join a room, take it and append a id (a crc32 of the host's name possibly) and forward it to a server. The server will now forward the packet to the host (It knows where to send it, it reads the id) and appends the IP/Port of the sender. The host will now receive the packet from the server containing the original senders IP/Port, he will now send a packet to the original sender and that's pretty much it, holepunching is done :)

For this to work I would've created another thread that keeps sending a keep alive packet each 30seconds or so to the server, this is where the players announce their ids. The server will save the id/ip+port combo and store it, this way it always knows where to forward the packets when someone tries to join a game.

This is supposed to be a fully UDP solution, no changes or any kind of interaction with the pvpgn server are required.

Ok, so pretty much the same thing except you are hooking send and recv wsock32.dll instead of create and join storm.dll and bne.exe, and using player names instead of game names.

Requires you to be able to identify "join" packets, then persumably store and resend them after the host has responded, or does the game do some retrys? This is why I hooked the join function so the hole punching is done before the join packet is sent.

As to it being "fully UDP" regardless you still need an outgoing connection to the server, I don't know why you would want to keep pinging the server with UDP when this is what TCP does automatically, why not just use TCP and not worry about it?

Personally I think hooking create and join is a better idea than messing with/adding latency to all the in-game packets as well. I've never messed with packet spying/modding/injecting for the game, although I understand there were some oldschool hacks that worked that way.

Are the "join" packets the same for every version of the game?

Ultimately it seems a bit more complicated than using the framework I have already provided, but if you can make it work then great! It would be very neat to just have a single dll that can be dropped into an existing installation. :)

-- edit --

BTW if anyone successfully uses my interface as part of a solution you can keep all of tk's $500, it's provided free in the hope that someone has time to do the work.
Title: Re: Nerd's Corner
Post by: Lambchops on May 02, 2019, 08:33:37 AM
              Warcraft II Plugin Framework

                                              ( including demo plugins )
 


To install download the zip file attached to this post and copy/replace its contents into a combat43 or Warcraft II BNE 2.02 installation.
*Should also work for any versions earlier than 4.3 - AFAIK they all use the same wc2 .exe file.

Currently tested and working with Windows 10, 7 and XP.


Note: The plugin framework currently only supports BNE 2.02 (Combat Edition 4.3 or earlier), it does not support CE 4.4 / GOG version. If there is a demand it can be ported at a later date.


  ----------------------


This will install a small file called "LC.dll" and make a few modifications to Warcraft II BNE.exe that link it.

A "plugins" folder will be created in the wc2 folder. Plugins can be placed in this folder will be automatically loaded when you run wc2.

This will allow a variety of mods to be easilly installed/uninstalled by users.

If there is nothing in the "plugins" folder, there is no change to how the game functions.

  -------------

For developers:
Spoiler
A plugin is simply a dll file that has the extension changed to "w2p".
There are currently only 3 hook points, although I may add more in the future if there is a demand.

The hook points can be accessed by exporting appropriately named functions from a plugin dll.

w2p_init has no arguments and is called when the exe is first started.

create_game will be passed a pointer to the game name and called when the player creates a game.

join_game will be passed a pointer to the game name and called when the player joins a game.

screen_update will be passed a value that describes the current game screen and will be called immediately before each screen update.

... so to make a simple plugin all you need to do is make a dll file that exports one function called "w2p_init" that takes no agruments, then rename it to "MyPlugin.w2p" or whatever and put it into the "plugins" folder. Your plugin will then be injected into the WC2 process when you next run it.

I will try to do some examples later when time allows.


   ---------



There are 4 example plugins included. If you don't want any of them, you can disable/enable them individually just by moving them in or out of the plugins folder (of course exit WC2 first then restart).





   ----------

   The "Lobby Map" plugin



(http://forum.war2.ru/index.php?action=dlattach;topic=4910.0;attach=3008)


The "lobby map" Plugin gives you a preview of the map in the pre-game lobby.

  -----------------


   The "Game Time" plugin


(http://forum.war2.ru/index.php?action=dlattach;topic=2703.0;attach=3019)


The "Game Time" plugin just adds a small game timer to the in game screen.


     --------------



   The "Chop Bars" plugin



(http://forum.war2.ru/index.php?action=dlattach;topic=2703.0;attach=3017)

The "Chop Bars" plugin gives you an on-screen progress bar for chopping peons that you own and are selected.


       ------------



   The "Allied Colors" plugin


(http://forum.war2.ru/index.php?action=dlattach;topic=2703.0;attach=2177)


The "Allied Colors" plugin give you the option of displaying all allies in blue and all enemies in red on the mini-map.
Press F2 to toggle this on/off. It is off by default.

   ----------------------


This is still in development, but appears to be working and stable for me .... please test! :)



                                                               :critter:



Changelog
-------------
0.1 initial hosting support
0.1.1 plugin framework
0.1.2 screen_update hook
0.1.3 compatability fix for later OS
0.1.3a fix for timer plugin glitch
0.1.3b fix for chop bars in single player mode
          added CPU saver plugins


Title: Re: Nerd's Corner
Post by: shesycompany on May 02, 2019, 09:40:57 AM
im not seeing the map as a host?  installed to 2.02 bnet and created tvb
Title: Re: Nerd's Corner
Post by: Lambchops on May 02, 2019, 09:51:34 AM
im not seeing the map as a host?  installed to 2.02 bnet and created tvb


--- edit ---


This problem fixed with v0.1.2

( was an issue with custom ddraw )
Title: Re: Nerd's Corner
Post by: shesycompany on May 02, 2019, 10:07:26 AM
win7 here ...yeah redone it to my ru version thats outside program files...still not getting to display.

its more than likely me ..need another machine to test.
Title: Re: Nerd's Corner
Post by: shesycompany on May 02, 2019, 10:42:04 AM
yup lc and lamb   wait and let someone else test my machine is a known pos..blue screens the works
Title: Re: Nerd's Corner
Post by: shesycompany on May 03, 2019, 10:24:28 AM
what os you on lamb?  ive tried everything u said still zip.
Title: Re: Nerd's Corner
Post by: Certified MENSA Genius Brain (smart) on May 03, 2019, 10:40:38 AM
Have you ever seen that program that automatically generates a new map?  That would be a cool plug-in, host runs it and it generates the map and then you host, and instead of showing the thumbnail preview it shows a big "?" and everyone has to explore, because nobody has seen it...
Title: Re: Nerd's Corner
Post by: shesycompany on May 03, 2019, 11:08:31 AM
warcraft 2 randomizer
Title: Re: Nerd's Corner
Post by: Lambchops on May 03, 2019, 11:28:02 AM
Have you ever seen that program that automatically generates a new map?  That would be a cool plug-in, host runs it and it generates the map and then you host, and instead of showing the thumbnail preview it shows a big "?" and everyone has to explore, because nobody has seen it...

Yeah that would be cool. You could make a plugin that makes a random map and hosts it, but people could still look at the pud file and cheat...

Have you tested the plugin framework yet? :)

Title: Re: Nerd's Corner
Post by: Lambchops on May 19, 2019, 10:29:26 AM
im not seeing the map as a host?



Turns out the updated ddraw.dll that a lot of people are using is great for the game but is missing most of the standard Windows API functionality so the methods I was using to display things on the screen were not working with that.

V0.1.2 Hooks the WC2 internal screen update so is compatible with all direct draw versions.

V0.1.3 Has fixed compatibility issues with later versions of windows.


Have updated THIS (http://forum.war2.ru/index.php/topic,2703.msg78016.html#msg78016) post with the new version.


Please Test :)



Title: Re: Nerd's Corner
Post by: Lambchops on June 13, 2019, 02:39:32 AM

Mini-Map Black to Grey Plugin

Changes the mini-map display color for the black player to a lighter shade of grey.


This is a very simple plugin that just changes 1 byte in the wc2 process, heres the source:

Code: [Select]
#include <windows.h>

// export a "w2p_init()" function this will run once when wc2 loads


extern "C" __declspec (dllexport) void w2p_init(){       
       
    // declare a pointer to a BYTE
    BYTE* bytePointer;
     
    // make it point to the mini-map black location
    bytePointer = (BYTE*)0x4A48B1;
   
    // set the byte to grey (0xEA)
    *bytePointer = 0xEA;   
    //   ...could also use
    //   - 0xFD Bright Pink
    //   - 0xDE Dark Purple
    //   - 0xD2 Dark Red
    //   - 0xE3 Dark OJ
 
   
}

BOOL APIENTRY DllMain (  HINSTANCE hInst, DWORD reason, LPVOID reserved ){ return TRUE; }



Just build that as a DLL file then change the filename from .dll to .w2p and put it in the "plugin" folder.

This source can be easily modified to test other mods also if you want.



Title: Re: Nerd's Corner
Post by: Delete mine too on June 13, 2019, 08:56:24 PM

Mini-Map Black to Grey Plugin

Changes the mini-map display color for the black player to a lighter shade of grey.


This is a very simple plugin that just changes 1 byte in the wc2 process, heres the source:

Code: [Select]
#include <windows.h>

// export a "w2p_init()" function this will run once when wc2 loads


extern "C" __declspec (dllexport) void w2p_init(){       
       
    // declare a pointer to a BYTE
    BYTE* bytePointer;
     
    // make it point to the mini-map black location
    bytePointer = (BYTE*)0x4A48B1;
   
    // set the byte to grey (0xEA)
    *bytePointer = 0xEA;   
    //   ...could also use
    //   - 0xFD Bright Pink
    //   - 0xDE Dark Purple
    //   - 0xD2 Dark Red
    //   - 0xE3 Dark OJ
 
   
}

BOOL APIENTRY DllMain (  HINSTANCE hInst, DWORD reason, LPVOID reserved ){ return TRUE; }



Just build that as a DLL file then change the filename from .dll to .w2p and put it in the "plugin" folder.

This source can be easily modified to test other mods also if you want.





Any functionality to draw to warcraft 2 screen? What about an array of bytes sample also. It would then be perfect to project! Thanks brother.
Title: Re: Nerd's Corner
Post by: Lambchops on June 13, 2019, 10:41:59 PM

Any functionality to draw to warcraft 2 screen? What about an array of bytes sample also. It would then be perfect to project! Thanks brother.


Yeah sure. Sorry not finding much time to document all of this.... still working 6 days a week ( and sleeping 1 day )

For an array of bytes, you can just declare the array in your source then use memcpy or CopyMemory etc. Will try to do an example later, but you can probably work that out.

Here's the game timer plugin. It demonstrates writing a string on a bitmap, then pasting that bitmap to the wc2 screen inside the display hook.

... uses:

paste_string(clock,0,0,&clockbuf[0],4,CLOCK_COLOR);

clock is the bitmap handle
(0,0) is target co-ords on the bitmap
&clockbuf[0] is the source ANSI string
4 is the font size (only supports 4 and 6 currently)
CLOCK_COLOR is the pixel value to set on the bitmap

this is done once per second to update the bitmap, then in the sccreen display hook it uses:

wc2_trans_paste(clock,CLOCK_X,CLOCK_Y);

to paste the "clock" bitmap onto the screen buffer at co-ords (CLOCK_X,CLOCK_Y)
(assumes 0 pixels are transparent)

These functions are exported from LC.dll
Have a look at lamb.h and lamb.cpp for others

Will try to document these further later.



dllmain.cpp
Code: [Select]
                                                         //
     /////////////////////////////////////////////////////
    //   Example dll for Warcraft II plugin framework  //
   /////////////////////////////////////////////////////
  //                                    Lambchops 2019
 


// *** This is a poor way of implementing a game timer.
// Shoud really be re-written to use GetSystemTime() or similar,
// but it makes for a simple example this way.


#include <windows.h>
#include <lamb.h>

// constants for the in-game screen
#define LOC_INGAME_H 1684300900
#define LOC_INGAME_O 2155905153


// display the timer here
// * using the top of mini-map to guarantee that this part
// of the screen is updated every second *
#define CLOCK_X         22
#define CLOCK_Y         24


// color for pixels on timer bitmap
#define CLOCK_COLOR   0xFE


BOOL game_timer_on = FALSE;

// count the number of game ended signals
BOOL tick_out = 0;



int  game_secs  = 0;
int  game_mins  = 0;
int  game_hours = 0;
int  game_days  = 0;

// allocate a buffer to store timer as a string
CHAR clockbuf[16];

// create a little 32x6 bitmap to draw timer string on to
HMIBMP* clock = make_bitmap(32,6,8);

// temp storage for game "location" value supplied
// to "screen_update()" by the framework
DWORD loc;



BOOL in_game(){
    // return TRUE if we are in a game
    return (loc==LOC_INGAME_H||loc==LOC_INGAME_O);
}


void reset_timer(){
    tick_out  = 0;
    game_secs = -1;
    game_mins = 0;
    game_hours= 0;
    game_days = 0;     
}

void game_tick(){
    // add 1 second to game time

    game_secs++;
    if(game_secs==60){
        game_secs=0;
        game_mins++;
        if(game_mins==60){
            game_mins=0;
            game_hours++;
            if(game_hours==24){
                game_hours=0;
                game_days++;
            }
        }
    }

    // redraw the timer display bitmap //

    wsprintf(&clockbuf[0],"%2.2d:%2.2d:%2.2d",game_hours,game_mins,game_secs);         
    zero_bitmap(clock);   
    paste_string(clock,0,0,&clockbuf[0],4,CLOCK_COLOR);
}


void CALLBACK TimerProc(HWND hwnd,UINT uMsg,UINT idEvent,DWORD dwTime){
    // this is called every 1 second by the system timer we set up below
   
    if(game_timer_on){
        if(in_game()){
            // update time by 1 second
            game_tick();
            tick_out = 0;
        }else{
            if(tick_out>1){
                // = 3rd miss for in_game()
                //( location constant appears to occasionally glitch on
                //  some systems - possibly a ddraw thing ?? )
                // game ended
                game_timer_on = FALSE;
            }else{
                game_tick();
                tick_out++;     
            }
        }
    }else{
        if(in_game()){
            // game started
            game_timer_on = TRUE;
            reset_timer();
            game_tick(); 
        }       
    }
}



////// EXPORTED FUNCTIONS FOR THE FRAMEWORK TO CALL ///////

// called once at startup
extern "C" __declspec (dllexport) void w2p_init(){
    // Create a timer that ticks every 1 second     
    SetTimer(NULL,0,1000,TimerProc);
}



// called every screen update
extern "C" __declspec (dllexport) void screen_update(DWORD location){
    loc=location;
    if(game_timer_on){
        // paste the time display bitmap onto the game screen ( pixel 0 = transparent )
        wc2_trans_paste(clock,CLOCK_X,CLOCK_Y);
    }
}



BOOL APIENTRY DllMain (  HINSTANCE hInst, DWORD reason, LPVOID reserved ){ return TRUE; }



lamb.h
Code: [Select]
#include <windows.h>


#ifndef _LAMB_
#define _LAMB_

extern "C" {
    typedef struct hmibmp {
        BITMAPFILEHEADER* pFile;
        BITMAPINFOHEADER* pInfo;
        RGBQUAD*          pPal;
        BYTE*             pBits;
        int               width;
        int               height;
        int               bpp;
        int               linew;
        int               usage;
        int               size;
    }HMIBMP;
}

//hmibmp.inc
extern "C" typedef HMIBMP* (__stdcall *pfnmakebmp )(int w,int h,int bpp);
extern "C" typedef void    (__stdcall *pfnfreebmp )(HMIBMP* bmp);
extern "C" typedef int     (__stdcall *pfnzerobmp )(HMIBMP* bmp);
extern "C" typedef void    (__stdcall *pfnsavebmp )(CHAR* path,HMIBMP* bmp);
extern "C" typedef void    (__stdcall *pfnsavejpg )(CHAR* path,HMIBMP* bmp,int quality);
extern "C" typedef void    (__stdcall *pfnperfbmp )(HMIBMP* bmp);
extern "C" typedef void    (__stdcall *pfncopyimg )(HMIBMP* src,int scrx,int srcy,int srcw,int scrh,HMIBMP* dst,int dstx,int dsty,int transp);
extern "C" typedef int     (__stdcall *pfncopyfull)(HMIBMP* dstbmp,HMIBMP* srcbmp,int transp);
extern "C" typedef void    (__stdcall *pfndispimg )(HDC destDC,int x,int y,int w,int h,HMIBMP* bmp,int dx,int dy,int dw,int dh);
extern "C" typedef void    (__stdcall *pfnsetpal  )(HMIBMP* bmp,LPVOID palette);
extern "C" typedef void    (__stdcall *pfndrawrect)(HMIBMP* bmp,int x,int y,int w,int h,int color);
extern "C" typedef HMIBMP* (__stdcall *pfnsizebmp )(HMIBMP* bmp,int w,int h);
extern "C" typedef HMIBMP* (__stdcall *pfnscalebmp)(HMIBMP* bmp,int scale);
extern "C" typedef void    (__stdcall *pfnsetpixel)(HMIBMP* bmp,int x,int y,int pval);
extern "C" typedef void    (__stdcall *pfnpastestr)(HMIBMP* bmp,int x,int y,CHAR* lpsz,int point,int color);
extern "C" typedef void    (__stdcall *pfnwc2tpast)(HMIBMP* bmp,int x,int y);


extern pfnmakebmp      make_bitmap;
extern pfnfreebmp      free_bitmap;
extern pfnzerobmp      zero_bitmap;
extern pfnsavebmp      save_bitmap;
extern pfnsavejpg      save_jpeg;
extern pfnperfbmp      perforate_bitmap;
extern pfncopyimg      copy_image;
extern pfncopyfull     copy_full_image;
extern pfndispimg      display_image;
extern pfnsetpal       set_palette;
extern pfndrawrect     draw_rect;
extern pfnsizebmp      size_bitmap;
extern pfnscalebmp     scale_bitmap;
extern pfnsetpixel     set_pixel;
extern pfnpastestr     paste_string;
extern pfnwc2tpast     wc2_trans_paste;

#endif

lamb.cpp

Code: [Select]
#include <windows.h>
#include <lamb.h>


HMODULE hLambDll = LoadLibraryA("LC");

pfnmakebmp  make_bitmap         = (pfnmakebmp )GetProcAddress(hLambDll, "make_bitmap"         );
pfnfreebmp  free_bitmap         = (pfnfreebmp )GetProcAddress(hLambDll, "free_bitmap"         );
pfnzerobmp  zero_bitmap         = (pfnzerobmp )GetProcAddress(hLambDll, "zero_bitmap"         );
pfnsavebmp  save_bitmap         = (pfnsavebmp )GetProcAddress(hLambDll, "save_bitmap"         );
pfnsavejpg  save_jpeg           = (pfnsavejpg )GetProcAddress(hLambDll, "save_jpeg"           );
pfnsizebmp  size_bitmap         = (pfnsizebmp )GetProcAddress(hLambDll, "size_bitmap"         );
pfnscalebmp scale_bitmap        = (pfnscalebmp)GetProcAddress(hLambDll, "scale_bitmap"        );
pfnperfbmp  perforate_bitmap    = (pfnperfbmp )GetProcAddress(hLambDll, "perforate_bitmap"    );
pfncopyimg  copy_image          = (pfncopyimg )GetProcAddress(hLambDll, "copy_image"          );
pfncopyfull copy_full_image     = (pfncopyfull)GetProcAddress(hLambDll, "copy_full_image"     );
pfndispimg  display_image       = (pfndispimg )GetProcAddress(hLambDll, "display_td_image"    );
pfnsetpal   set_palette         = (pfnsetpal  )GetProcAddress(hLambDll, "set_palette"         );
pfndrawrect draw_rect           = (pfndrawrect)GetProcAddress(hLambDll, "draw_rect"           );
pfnsetpixel set_pixel           = (pfnsetpixel)GetProcAddress(hLambDll, "set_pixel"           );
pfnpastestr paste_string        = (pfnpastestr)GetProcAddress(hLambDll, "paste_string"        );
pfnwc2tpast wc2_trans_paste     = (pfnwc2tpast)GetProcAddress(hLambDll, "wc2_trans_paste"     );






Title: Re: Nerd's Corner
Post by: Qanon on June 20, 2019, 11:26:50 PM
works noww

              Warcraft II Plugin Framework

       ( including demo plugins )
 

This will install a small file called "LC.dll" and make a few modifications to Warcraft II BNE.exe that link it.

A "plugins" folder will be created in the wc2 folder. Plugins can be placed in this folder will be automatically loaded when you run wc2.

This will allow a variety of mods to be easilly installed/uninstalled by users.

If there is nothing in the "plugins" folder, there is no change to how the game functions.

  -------------

For developers:
Spoiler
A plugin is simply a dll file that has the extension changed to "w2p".
There are currently only 3 hook points, although I may add more in the future if there is a demand.

The hook points can be accessed by exporting appropriately named functions from a plugin dll.

w2p_init has no arguments and is called when the exe is first started.

create_game will be passed a pointer to the game name and called when the player creates a game.

join_game will be passed a pointer to the game name and called when the player joins a game.

screen_update will be passed a value that describes the current game screen and will be called immediately before each screen update.

... so to make a simple plugin all you need to do is make a dll file that exports one function called "w2p_init" that takes no agruments, then rename it to "MyPlugin.w2p" or whatever and put it into the "plugins" folder. Your plugin will then be injected into the WC2 process when you next run it.

I will try to do some examples later when time allows.


   ---------



There are 4 example plugins included. If you don't want any of them, you can disable/enable them individually just by moving them in or out of the plugins folder (of course exit WC2 first then restart).





   ----------

   The "Lobby Map" plugin



([url]http://forum.war2.ru/index.php?action=dlattach;topic=4910.0;attach=3008[/url])


The "lobby map" Plugin gives you a preview of the map in the pre-game lobby.

  -----------------


   The "Game Time" plugin


([url]http://forum.war2.ru/index.php?action=dlattach;topic=2703.0;attach=3019[/url])


The "Game Time" plugin just adds a small game timer to the in game screen.


     --------------



   The "Chop Bars" plugin



([url]http://forum.war2.ru/index.php?action=dlattach;topic=2703.0;attach=3017[/url])

The "Chop Bars" plugin gives you an on-screen progress bar for chopping peons that you own and are selected.


       ------------



   The "Allied Colors" plugin


([url]http://forum.war2.ru/index.php?action=dlattach;topic=2703.0;attach=2177[/url])


The "Allied Colors" plugin give you the option of displaying all allies in blue and all enemies in red on the mini-map.
Press F2 to toggle this on/off. It is off by default.










   ----------------------



To install download the zip file and copy/replace its contents into a combat43 installation.
*Should also work for any versions earlier than 4.3 - AFAIK they all use the same wc2 .exe file.

Currently tested and working with Windows 10, 7 and XP.

  ----------------------

This is still in development, but appears to be working and stable for me .... please test! :)


Note: The plugin framework currently only supports BNE 2.02 (Combat Edition 4.3 or earlier), it does not support CE 4.4 or the GOG version. If there is a demand it can be ported at a later date.



                                                               :critter:


Title: Re: Nerd's Corner
Post by: Lambchops on June 22, 2019, 07:22:00 AM
Timer Plugin Fix.

RandomPeasant and Warbux reported a bug where the game timer would think the game had ended and reset itself. This version appears to fix that issue.

I have updated the plugin framework zip file with the new version.

If you already have the PF installed you can just dl the attached file and put it in your plugins folder (replace the old version that is there)

Title: Re: Nerd's Corner
Post by: Lambchops on July 22, 2019, 07:42:09 AM
                             PALETTE ANIMATION

I have idly wondered more than one about the neat water animation you see in WC2 on the coastlines. It's something I would have expected to have tripped over in the exe when looking for something else, but never have.

Turns out thats because its done with palette animation, which is pretty amazing considering how good it looks. Next time you're in game, have a look at the coast then remember that no pixels are changing at all, its just the palette.

I noticed this when messing around with changing the in-game unit graphics... some of the bits that were supposed to be brown kept turning blue, so I replaced the great hall graphics with a 128x128 palette grid and discovered that quite a bit of the wc2 palette is animated in-game. Most of it is for water effects plus entry 3 just flashes from green to red and back - which is obviously the color it uses for a unit that is being attacked on the mini-map.

(http://forum.war2.ru/index.php?action=dlattach;topic=2703.0;attach=3123)

The palette animation doesn't show up in warvid. Anybody ever noticed your units don't flash red on the minimap in warvid? Twitch mostly picks it up.

Anyway you can see what's going on in the attached vid, if anyone's interested.

BTW yes I am still working on an updated plugin framework...


Title: Re: Nerd's Corner
Post by: Zelya on July 22, 2019, 03:33:22 PM
The same for War1. This allows to avoid back tiles layer redrawing every time. Also as I remember this feature is used for building frame coloring.
Title: Re: Nerd's Corner
Post by: Lambchops on July 23, 2019, 07:31:08 AM
The same for War1. This allows to avoid back tiles layer redrawing every time. Also as I remember this feature is used for building frame coloring.

OK. I've never looked at the war1 code. "Smacker" which is the video format used for the into, campaign cutscenes and channel banner ads also uses 8-bit palette animation heavily.

Title: Re: Nerd's Corner
Post by: mousEtopher on August 09, 2019, 01:38:27 PM
i finally got the plugin system installed & it's really nice!! it's working for the non-latest version of war2combat & the latest version of fois's ddraw with the moveable window, but i did notice 2 things:

- the map in game lobby disappears & reappears randomly, sometimes when alt-tabbing
- the new warcraft ii bne.exe kills insight? I get this popup when i click "record"

(https://i.imgur.com/ijoOtf4.png)

also jw is the CpuSaveC.w2p the same as the console cpu savior?
Title: Re: Nerd's Corner
Post by: Lambchops on August 20, 2019, 09:12:41 AM
Hi @mousEtopher I'm sorry I missed this when you posted it.

i finally got the plugin system installed & it's really nice!! it's working for the non-latest version of war2combat & the latest version of fois's ddraw with the moveable window, but i did notice 2 things:

- the map in game lobby disappears & reappears randomly, sometimes when alt-tabbing

Thanks :) Glad you like it.

Not sure about movable window stuff but there was a bug that I left as a 'feature' lol. The map disappears when you start typing then comes back when you move the mouse. I thought it was useful to still be able to see the game name/pw if you wanted to so I left it as it was.

Interestingly I have noticed that it no longer does this on my system although I have not tried to correct it at all. I presume something else I have changed when further developing has affected it.

There is also an occasional glitch when you join the map displays too early and is overwritten by the lobby screen so it isn't initially visible. If you just touch the race selector it will display correctly.

Same thing when downloading a new map... just touch the race selector.

The only other issue im aware of is if you are helping someone test a map while they are developing it. If you already have a copy of the map it will display when you enter the lobby, but then when you dl the new updated version you will still see the old one displayed unless you exit the lobby after the dl then rejoin. Filed it under "meh... not worrying about it".

- the new warcraft ii bne.exe kills insight? I get this popup when i click "record"

The plugin framework itself doesn't affect insight at all. The problem is that insight checks the exe and because it has been modded it just refuses to run.

This can be fixed by going back to the standard Warcraft II BNE.exe using the Launcher.exe program ... this just applies the same mods in memory so that when insight checks the exe it doesn't have a problem.

The only problem with this is that if you do it that way then you can't use iL's ploader to load the game so you can't use the AH.

I tested a way to make it all work, by renaming "Warcraft II BNE.exe" to "Warcraft II BNE2.exe" then renaming the Launcher.exe to "Warcraft II BNE.exe" then getting the ploader to run the launcher and that all worked, but of course I had to build a custom Launcher that had the BNE2.exe filename in it.

... blah blah blah - anyway none of this will be a problem if iL puts the launcher code into the ploader then it will all work together harmoniously.


also jw is the CpuSaveC.w2p the same as the console cpu savior?

It's based on the same principle. iL asked me to have a crack at it because he was having issues with his one, so I incorperated it as a plugin.

There are actually 2 cpusaver plugins bacause there are to main execution loops in wc2. One that runs in the game and another that runs when you are in the channel. iL's cpu saviour only worked in game and apparantly there were some latency issues with it idk.

CpuSaveC.w2p is for the channel. It will cut your CPU usage when you are not in games. I have included it as standard in the plugins zip.

CpuSaveG.w2p is for in game. It will cut your CPU usage when you are in game, including the pre-game lobby... this screen is from the pre-BNE era and is internally part of the "game".

I have not included the in-game saver as standard simply because it hasn't been thoroughly tested under all conditions and I didn't want people to think that the plugin framework was causing latency (just in case), although it seems to work fine on my system with no issues.



Title: Re: Nerd's Corner
Post by: shesycompany on August 26, 2019, 12:20:06 AM
got another user wanting it  :newthumbsup: its the only way to play war2