Jump to content

  • Log In with Google      Sign In   
  • Create Account

We're offering banner ads on our site from just $5!

1. Details HERE. 2. GDNet+ Subscriptions HERE. 3. Ad upload HERE.


Member Since 12 Mar 2005
Offline Last Active Yesterday, 07:02 PM

#5193931 Steam advertising and analytics

Posted by frob on 21 November 2014 - 02:12 AM

Let`s talk here about marketing Steam store page, analytic tools and services that help understand and predict Steam traffic and how to drive greater traffic on the page from WEB and from Steam community.



I recommend you use analytic tools. Build them into dashboards that the marketing and SoCom and similar groups refer to regularly, and operations groups refer to at least daily.


Some analytics events should trigger alerts, ranging from emails to pager alerts and phone calls. Something that makes your 24/7 online game go down deserves a bunch of phone calls even at 3:00 AM. If analytics shows the number of current players drops from 45,000 to 300 over a matter of minutes then dev teams and op teams should likely be called no matter the hour.


Other analytics should be reviewed less often. Running an A/B style marketing campaign you can compare how effective each of the options are, and then change the stuff around.  Stats like DAU and MAU are important, as are things like average paying users per day, average payment from paying users per day, as are stats tracking where in the pipeline of sales conversions people are getting stuck.  If they put items in the cart but never complete the transaction, you need to know so you can fix the process. If not enough paying players are costing you server resources, you need to know that too.


Other analyitcs are useful for design of future games. Collect them, process them, use them, love them.

#5193927 C# .Net Open Source

Posted by frob on 21 November 2014 - 01:43 AM

C# will be more attractive now -- to be perfectly blunt, C# is a better language than Java, full-stop.

So much this. I have worked with both languages on and off ever since 2004.  I am currently doing Java work. 
C# is already attractive and I strongly prefer it over Java. It just feels better.  Mono has some quirks but they are not significantly worse than JVM quirks, and just like in Java land, you can learn the quirks and work around them.
Opening the MS implementation means they can hopefully fix so many of those little quirks like the foreach() overhead and nested iterator serialization concerns. 

Microsoft bought a company called SyntaxTree who already made and sold a plugin called UnityVS


I love UnityVS. When I got the email from Microsoft that announced they had acquired UnityVS and would be contacting the purchasers with additional information I was very concerned.


Was it going to be Microsoft embrace/extend/extinguish, or a case of promoting it to world class software? 


Sadly the jury is still out on this.

If there was a easy fix to get away from the 'stop the world' garbage collector in there


This is by design of the language, for both C# and Java. Stop the world very rarely happens when you follow a few simple development rules.
If you follow a few simple practices (and sometimes a few complex practices) this is actually an amazing feature of the languages.
Let me explain:
First, there is a background-priority task, or "invisible" process, or aspect of the virtual machine, that runs the algorithms.  There are multiple types of algorithms with different results.
Concurrent Mark Sweep (CMS) is found both in modern JVMs and Mono, with either the UseConcMarkSweepGC option in Java or the gc=sgen flag in Mono.  As a background work while your program is busy loading data or sending graphics commands over the bus or otherwise has some spare time on any processor (which is quite often) it will implement a concurrent mark algorithm. This travels the live objects and marks them as reachable, then it runs a sweep to find and release unreachable memory. It uses a concurrent lock on the memory block, but since this is a low-priority process and runs on idle there is no cost.  It is effectively free since it runs during idle, although there is an extremely small but measurable cost in memory to pay for the concurrent marking. 
Then there is a second version called Mark/Sweep/Compact (MSC) that does the same thing, but does invoke some rare "stop the world" behavior.  In addition to the mark and sweep, there is a compact phase that effectively defragments your memory. While it does stop the world, it also typically runs as a low-priority task so it only hits on idle.  When enough objects are ready to move to a different generation of the GC (in Mono the generations are 'Nursery', 'Major Heap', in Java they are "Young Collection" and "Old Space Collection") the threads referencing the memory are paused, a small chunk of memory is migrated from one location to another transparently to the application, and the threads are resumed.
In normal operation, CMS is normally quietly running in the background sweeping up objects you no longer need. Critically: THIS IS A TASK RUN DURING IDLE. You do not see it, you do not pay any significant cost for it. Occasionally, when there is a lot of accumulated 'old' stuff, the "compact" algorithm will pause the few threads referencing something and move it between generations or move it to defragment memory. Critically: THIS IS ALSO A TASK RUN DURING IDLE, but with the caveat that it can potentially stick around a few microseconds into when something would normally get scheduled.


Also note that there is a secondary memory pool for long-term objects.  This includes things like models and textures and audio. You don't want it moved around so you specifically load it up into the older-school style of managed memory, with a note I'll cover with the language comparison.


In very exceptional operation, at times when you are trashing memory or leaking resources or doing other stupid bugs, you will run out of memory in one of the pools. In this case it forces the compact to run immediately. This stops the world in the middle of the action and blocks until the memory is scanned. This is the bad one that people complain about.


So let's compare how this works with the C++ model.


In C++ you typically free memory in destructors and also free memory as a task in the middle of other processing.  Most game studios have semi-strict rules about when you can allocate memory and (with various degrees of enforcement) only permit you to allocate/release memory during times like level loading or specially designated transitions.  The reason for this restriction is that collection (calling delete or free) takes place immediately, and also because if you leave things on the heap it can badly fragment memory. Memory fragment is a lesser concern on the PC with virtual memory reallocations, but is still a minor problem on PC and a major concern on devices. The processing is not delayed until idle, the heap modifications takes place during the busy section of your code.  In the roughly 11 major engines I have worked with zero of them displaced the heap processing to a low priority process. In every engine it was entirely up to the developers to not fragment memory, and sadly very often there would be a few bits here and there that would get missed and every game ships with a slowly fragmenting memory space.


So with C++ you get to pick and choose when GC runs, but in my experience this universally means that GC runs at the worst possible time, it runs when the system is under load.  With modern versions of both Java and C#, you do not get to chose when GC runs but it is almost always at the best possible time, it runs when the system is idle. On rare occasions it will slip into when you should not be idle, consuming on the order of 1/10,000 of your frame time. On extremely rare occasions (typically caused by bad/prohibited/buggy practices) it will unexpectedly run when the system is under load, exactly like C++ except not under your control.  Historically we log those extremely rare occasions and flag them for investigation and floggings. 


One of the great practices I learned years ago was the use of threads for organizational management.  THIS IS NOT A BEGINNERS ARCHITECTURE AND DOING IT WRONG CAN BE FATAL TO PERFORMANCE, do it with extreme caution and profiling. Effectively, inside the simulator each game object's specific allocations live only within that thread, and cross-thread data is very carefully designed to live in a lock-free environment. Typically the engine has all its allocations moved into the old generation early on, so when the "compact" algorithm is triggered it normally is triggered by game objects and only locks game objects. Each thread gets awoken (very carefully to avoid the stampede of elephants problem) within the pool and given the opportunity to update. So when the "compact" algorithm runs and needs to stop the world, the world it stops is only the single thread among many that are queued. The other simulator threads continue to execute. Since so many other threads are simultaneously scheduled the algorithm's lock has no net effect on performance. You may have several hundred pending tasks and a few get blocked, so the OS immediately picks up the next unblocked task without pause.


For a commercial environment where you can ensure those bad/prohibited/buggy practices are minimized the Java/C# model is far and away better for performance. So C++ you pay the cost during heavy load.  In C++/Java you you pay the cost during idle and stop-the-world conditions in practice do not stop the world at all, releasing memory is approximately zero cost.


For those still working in C++ only code and you're on a platform that supports managed code (C++/CLI) you can use the .net libraries to take advantage of gc-managed objects, I strongly suggest you investigate doing so. It is not a hard thing to change from * to ^ notation on the objects and done well it can give some big benefits for managing object lifetimes.



That is way more than I intended to right, but should cover it enough.  


tl;dr for this section: The modern GC algorithms in C# and Java are amazingly good, with a default model that completely exceeds the C++ end-of-life memory management model. 

#5193709 Runge-Kutta in a large solar system

Posted by frob on 19 November 2014 - 08:48 PM

Be aware that very few space-style games use actual real dimensions and scales, nor do they calculate actual physics for planetary bodies.


Think about what it means to have gravity and orbits around planetary bodies:  


You've got the moon that orbits Earth in about a month.  For a player looking at the Earth and their environment when rotating at that speed it will be indistinguishable from being stationary.  You've got satellites that are geostationary, that is, relative to the Earth they don't move at all. You've also got smaller bodies in lower orbits, the ISS orbits the Earth every 90 minutes, there are satellites that orbit even faster than that.


In other words, if you are planning on orbiting the planet you can make it any animation you want.  Zero relative is perfectly acceptable. High speed rotations are perfectly acceptable.


Since natural ranges include everything from stationary to high-speed motion, do whatever is easiest.  Normally that means a static scene.




Then when it comes to things like interplanetary travel, you either better allow for some kind of jump system, or a loading screen style transition between areas.  Figure that even if you allowed traveling at the speed of light it can still take 20 minutes to travel from Earth to Mars. If you want to have physics based travel you better have some really good music or something interesting for the player to do, because waiting around watching a space ship travel through the void is even more boring than level grinding. 




If I'm going to play a space game it isn't going to be "Realistic Simulator of the Voyager Probe, Year 37", but something like EVE Online with active play and completely fake but very engaging physics rules. 

#5193694 Having two arrays in the scene ?

Posted by frob on 19 November 2014 - 06:04 PM

Your post isn't very clear.


You have arrays of what? You have trees of what?


Modern systems transfer all the data like textures and vertex arrays and shaders over to the video card, then set a small number of parameters and instruct it to run a list of commands.  Then there is a single small transfer across the bus, and the card does all the work.  They also use the fact that certain operations on the card take more time and try to cluster them together. For example, changing textures and changing shaders takes time so they'll often batch up all the instances of an object and draw all of them so they only pay the cost once. Vertex arrays and textures will also be transferred once and then referred to by id forever after. 


The kind of lists and arrays you mention doesn't really sound like that.  They sound more like you are transferring the vertex arrays every frame. That is a burden on the bus and on memory, and should be avoided.

#5193552 Implementing bitwise not operation with only or and and?

Posted by frob on 18 November 2014 - 09:36 PM

This is homework. It is to get *YOU* to think, not to get *the community* to think.

There are many different reliable ways to do it. Remember, all you have to do is convert 1 to 0 and convert 0 to 1.

I hinted at five different options that I know would work. Depending on what other operations you have and what assumptions you can make, you might find many more. For example, are you working on a machine that uses 2's compliment numbers (like nearly all integer numbers these days)? What do negative numbers look like, relative to positive ones? Can you use that? There is a sixth potential option.

#5193529 Using RealWorld People in Games and law?

Posted by frob on 18 November 2014 - 04:54 PM

how close can i get, whats your experience...?



You are asking wrong questions. How fast can you speed before you get caught? How close to the edge of a cliff can you drive without falling off? How many banks can you rob without getting caught? These are all along the same vein. The question should never be "how much can I get away with."


Don't do it at all.  Don't even approach the edge.  Stay far away from it.  Make your own stuff and be creative.

#5193526 Implementing bitwise not operation with only or and and?

Posted by frob on 18 November 2014 - 04:49 PM

If the only options available to you are & and | and a single variable, you can't do it.


But give me some little bit more -- such as a conditional, an xor, even the pair of addition and bit shifting or addition and bit masking -- and it becomes quite feasible.  


This is probably the lesson your instructor wanted you to learn with the question.

#5193471 How to estimate latency in one direction only

Posted by frob on 18 November 2014 - 11:32 AM

If there are simple ways to get unidirectional latency, I will use it because it's closer to what I need.


Simply, there are not.


There are complex methods to get it. There are expensive methods to get it.  For example, you could synchronize two atomic clocks and move them to the different locations and use those to compare the difference each direction, including accounting for dilation of time as you moved the clocks from one place to another.  Or you could determine the exact distances of fiber cable and distances of copper cable and the exact devices in the middle, then run though some complex equations.



Far easier is to just find the round trip and divide by two. This is close enough for most things.

#5193468 Using RealWorld People in Games and law?

Posted by frob on 18 November 2014 - 11:26 AM

There are several sets of laws, and they vary by country.


There are publicity rights, personality rights, celebrity rights, and public figure rights, to name a few.


There is a great deal of nuance involved. Exactly what information you present about them is important. Exactly how they are presented is important. A slight change in those from what was described can make your use slip from legal and easily defensible to becoming an infringing use that is hard to defend.


You really need to discuss the exact details with a lawyer. 

#5193332 is there a better way top refer to assets in a game?

Posted by frob on 17 November 2014 - 05:21 PM

I've seen both of those in practice, but ultimately this is rarely a concern on PC games.


Yes, there is a tiny cost of dealing with a text string.  That cost is completely dwarfed by the costs of IO.


Back on the small handheld era, with space measured in "megabits" and "kilobits", we used a macro solution similar to what was suggested.  Something like: 

result = LoadModel( MAKE_RESOURCE_KEY( "real_name", 0x12345) );

The macro would validate the name matched the hash and made an entry in some debugging logs.


But as phantom and others pointed out, that is a fairly rare operation and the result is a pointer. After that every time you deal with it you are working with a pointer instead so there is no concern.


Also, these days on the PC you are much less likely to pre-process all your resources down to integer IDs, and the cost of computing the IDs on the fairly rare times you need them is extremely small for simple hashing algorithms.  Even on SSD you're looking at an overhead of milliseconds for the disk read, spending a  microsecond on the rarely-executed hash is not going to be a performance concern.


Most of us are not on systems any more where encoding "filename.mus" in the source code causes too much data in the executable. If we really need a number we can hash it and use the result.


This is a solution to a problem we don't normally have any more.

#5193328 Why would this not compile... (c++)

Posted by frob on 17 November 2014 - 05:07 PM

Share please?


Sharing your solution helps others who may have a similar issue in the future.


I'm guessing from this error (warning: extended initializer lists only available with -std=c++0x or -std=gnu++0x) one of your items is a missing compiler option to enable something newer than the 2004 C++ standard.


And I'm guessing you also discovered some mismatched braces or a similar error in the header file.

#5193107 Why only rotation in degrees?

Posted by frob on 16 November 2014 - 11:20 AM

Those classes come from your code, not from OpenGL. (Or perhaps OpenGL ES, if that is the flavor you prefer.)


The questions are not things normally handled by OpenGL, but instead handled by your own math libraries.




When OpenGL operations require an angle, they near-universally require the angle in radians, not degrees. For quaternions, there are only a small number extensions that allow them, but an increasing number of popular shaders take them as parameters. I'm not aware of any function in the core API that accepts them.



In this case you seem to be referring to the Android SDK's class android.opengl.matrix, those are just a collection of static methods for manipulating float arrays. They aren't spectacular and games typically use their own libraries instead. They are extremely rudimentary classes for some basic functionality, but they are not high performance nor are they comprehensive of what most developers need.


You also seem to be referencing the android.renderscript.Matrix4f functionality, which is useful if you are using RenderScript, but it isn't directly portable with the OpenGL ES stuff.

#5192917 Resource management

Posted by frob on 14 November 2014 - 05:51 PM

I still claim people are misunderstanding me.

It's not a matter of discipline. No amount of discipline will prevent me from typing "teh" instead of "the" sometimes. We're all human, we all make mistakes - from typos to logic errors. If discipline fixed all that then no one would ever need to debug anything.

I'm simply advocating that, whenever possible, use the features of the language to enforce your policies in a way that you can catch violations at compile time. Or at least at runtime. Sometimes that's not possible, but for a large majority of things it is.

In the case of threading, locks enforce policies at runtime. If you find out they're slowing you down, then figure out ways to remove them (i.e. redesign) But don't waste a lot of time making your code harder to read and maintain in areas where your profiling tools are showing you that performance is not an issue. (And lockless code is harder to maintain because it doesn't protect you from mistakes)

I would argue the exact opposite of this.


This is not "for beginners".  Beginners do need systems that strictly enforce the rules. Beginners need safety scissors. Beginners need special pumpkin-carving knives rather than traditional paring knives. 


Game engine development is not a place for beginners. It is a place for system architects. While somewhat abrasive, I completely understand why Linus Torvalds chose to utterly reject c++ code from kernel development: the abstractions and safety nets are not free and in systems-level programming the cost of using them is sometimes unacceptably high. By rejecting C++ code from the kernel he also rejects an enormous volume of developers whose skills and understanding are less than stellar. Yes, it does introduce a cost to development. But the benefit is source code that strictly follows certain policies.  Discipline and policy adherence, not tools that hold your hand and wipe your bum, are critical.


As one of many examples, classic memory managers and classic destructors provide an excellent safety net.  Unfortunately they also present a terrible burden in some places, which is why many game development libraries provide an additional "throw all the memory away" option that avoids destructors and proper teardown. You need to follow policy correctly, you only use it when policy says it is safe because it is a potentially fatal function. Is it unsafe? Absolutely! It is a scalpel to be used with prudence and care. Similar functionality was partially added to C++11 because it is so prevalent in many industries, but in the hopes of giving a safe tool many people find the tool inadequate for their needs.  Because they ultimately chose 'safety' they made a tool that is unusable.


This is not a topic about beginners or junk code. This is a question about resource management inside an engine. That is system level work.




Pulling back toward topic:


Resource management.


You need to manage when resources come alive. You need to manage how they move through their life cycle from pre-load to loading to loaded to active to archived to discardable to unloaded. You need to manage when resources are destroyed.


ALL of those steps are policy based.


If you don't care about policy, any system could load data from any arbitrary data source and feed it directly to the graphics card. This situation does not scale well and is unlikely to perform well.


But we do care about policy. We follow policy strictly. We build systems around policy, such as building object pools, object loaders, and proxies/handles that can help you coordinate with objects as they move through their life cycles.



You write it is not a matter of discipline. I say it is ENTIRELY a matter of discipline and policy. You must have the discipline to use the tools provided, to use the model loader and the model cache rather than calling fread() to open your models. You must have the discipline to use your a carefully-designed lock manager policy, that you must always call AcquireLocks() and ReleaseLocks() every single time you work with locking objects.  You must have the discipline that every time you allocate memory you ensure that you release the memory or transfer ownership. You must have the discipline that every time you modify the source code to remove some functionality you also review the entire code base searching for comments about it and references to it and systems that use it indirectly and modify those as well.  You must have the discipline to run the automated tests before submitting the code even if it takes 10 minutes. You must have the discipline to always run and test the code in game, even if it takes several hours to test all the facets before submitting the code.  All of these are absolutely a matter of discipline and policy.


You write that you should let the compiler do it so you don't have to.  I agree that you should lean on the compiler when appropriate, you can make compile-time checks for a lot of features. You can build a tool with a list of functions that ensures you have acquired and released locks inside the function. You can lean on the compiler to ensure all references have been renamed or removed, you can lean on the compiler to ensure syntax is correct, you can lean on the compiler to do a lot of optimization, but you cannot blindly assume the compiler will be your parachute. It is quite common for the compiler to miss things.  But ultimately, the compiler must presume unless the programmer directly contradicts the language rules then the programmer is always right, only the programmer is responsible. You can tell the compiler to do something nonsensical and it will attempt to do it. It might make optimizations that eliminate dead code, or improvements to lift things out of loops or other sloppy programming, but beyond that the compiler will assume you are right. It is not the compiler, but the programmer and their discipline that ensures it is correct.


Sure as part of your careful, rigorously-designed policy you can create an object that obtains a lock and does so in a well-designed system. You can then write policy that tells programmers they must create an instance of the object, and policy that says what the object does, and policy that says what not to do. You can even write tools that help enforce the policy by validating the source code against custom-built tools.


But ultimately if the programmers violate the policy, either as a sin of commotion or a sin of omission, that is a failing of the programmer.  Discipline and policy are critical.



Object lifetimes and resource management is first and foremost a matter of policy.  A policy of when objects are created, and what is allowed to create them.  (And policies for what is forbidden from creating objects.) A set of policies for what systems own the objects and how they are treated in a wide variety of situations including exceptions. (And policies for how they are not to be handled, how they are not to be stored.) And policies for how objects are retired, interred, and destroyed. (And policies for how they are not to be destroyed.)  The code and classes and tools merely implement the policies.

#5192912 Z Fighting issue with armor pieces

Posted by frob on 14 November 2014 - 05:19 PM

Yup, there are many different variations on the theme of how to break down your depth buffer.


The classic original z-buffer just stores the distances as a floating point number. If you're familiar with how floats work they are higher precision at low number, lower precision at far numbers. Since they just subdivide the near and far plane it gives a very unequal distribution.


You've got traditional z buffer algorithm, then algorithms like w-buffer, logarithmic z, inverse z, irregular z, s-buffer, hierarchical z, and many more methods available to compute your depth buffer value.  You can even have depth buffer values based on compute shader results.  


There are a huge number of functions you can use, all that matters is that the result can be run through the graphics card's depth test function to give a clear less/equal/greater comparison. 

#5192806 Game dev team sharing code

Posted by frob on 14 November 2014 - 12:55 AM

Also, most free version control hosts are limited to open source projects. If you want to keep your stuff private you'll need a private hosting provider.  One of the site's partners, Assembla, offers 1GB of private hosting for free. Scroll to the bottom of any page and pick the Assembla link for more info.