Jump to content

Mumbles

Members
  • Posts

    691
  • Joined

  • Last visited

Blog Comments posted by Mumbles

  1. Ah, now one of these new APU motherboards was what I was asking you about in someone else's thread thread not too long ago. I was more interested in LE 2 generally rather than Crysis though. I see no reason why I shouldn't be OK for LE 2 - and it's got to be more powerful than my current GeForce 8800GT - that is showing its age now, but it's given 5 years loyal service...

     

    But, I was meaning one of the new (Steamroller?) architecture boards on the FM2+ socket, that haven't yet been released. The high power version of the Jaguar architecture if I've read things properly...

     

    These could be the things that bring affordable computers back in the home for the casual gamer who has been strongarmed into buying a console in the last generation.

  2. You can simplify your code quite a bit actually by using the mod operator... (Assuming it's C, which it looks like)

     

     

     

    //Mouse wheel checking
    m = LE.MouseZ();
    int CurrentTowerCount = 5; //Every time you add a tower, increment this - this should actually have a higher scope visibility than just this function, otherwise it will keep resetting this value to 5 towers (0 through 4) every time it checks for mouse movement
    if (prevM != m)
    {
    (selectionID += (prevM - m)) %= CurrentTowerCount; //If it's going the wrong way, swap the += for a -=
    SetNewCurrentTempTower();
    prevM = m;//I'm guessing you had this line as well...
    }

    • Upvote 1
  3. What sort of advantages does using TCP bring?

     

    Where speed isn't so crucial (RTS games for example) it does everything that reliable, ordered UDP does, but it's not handled by your application, it's basically handled by the OS. It's almost sure to be better optimised if it's part of the OS rather than having to do bits yourself.

     

    Currently I'm looking towards using both UDP and TCP side by side, both performing different tasks, but working in harmony:

     

    UDP for the vast majority of the data:

    Clients telling the server how they wish to move, or interact with the world

    The server keeping all clients informed about updates to the world, and other players. (These are only delta updates, up to 40 per second default)

     

    TCP for everything else:

    The server sending definite (timestamped) states of the world for clients to base their received updates from (no faster twice a second)

    Players chatting

    Downloading extra packages from the server (File transfer is one case where there is no point reinventing the TCP wheel on UDP).

    Latency measuring (Yes, it could go on the UDP socket, but I'm keeping that socket as clear as I can, it already has a very high frequency of packets on it)

     

    As for when would anything be ready to show? Months... at least.

     

     

    I realize you would be in effect "accepting" the connection first, but then immediately closing it with your client check function.

     

    I've since found out that actually, winsock's not as bad as I first thought. You don't have to wait for the peer to shutdown their socket before you can delete it. Using setsockopt you can change a value called SO_DONTLINGER to true (or 1 because it's C not C++). Now you can shutdown your socket as normal, but if you then proceed to call closesocket() before the remote peer shuts down, rather than crashing your application, it gives the remote peer error 10054 "connection reset by peer" on their next call to send() recv() or shutdown()

     

    It's just that SO_DONTLINGER is set to false (0) by default, but once it's changed you can pull the plug on any player you don't like without any warning, and without having to wait for them to shutdown too.

     

    There's also probably less to go wrong with this method than conditional accept, so I may end up not using that. Yes, it confirms to a different sort of trouble maker that your application is actually running, but I think that's probably too insignificant to spend too much time worrying about.

  4. Here is the correction: REMEMBER TO MAKE YOUR CHILD CLASS DESTRUCTOR VIRTUAL

     

    Not the parent class destructor? This is confusing... I thought virtual had no effect on classes that had no children...

     

     

     

    Mind you, not as confusing as this: I went to click the reply button, but instead clicked report (I don't think anything happened, but sorry anyway) and I got this message:

     

    [#10136] You do not have permission to report the item you are attempting to report.

     

     

    So if there actually was something nasty, who DOES have permission to report it?

  5. Did you read the article?

     

    I tried but the link pointed to my blog entry... A bit confusing since I've never heard of them before, but I think I'm starting to get the idea of what they are... I put "c++ virtual destructor" in Google and found this:

    http://www.programmerinterview.com/index.php/c-cplusplus/virtual-destructors/

     

    And I think Roland's answer says the same thing. So I can see why I might need it. Until I read that, I always thought that both constructors AND destructors were NEVER inherited from the base class because they had no name, but always had to be available if you wanted to use it. I think I've got a few classes to upgrade...

     

     

    Regarding your improvement to the struct... I've never seen that before... That's effectively a constructor? Might make things a bit neater, but normally if I return a pointer from an function (or member function), it will be allocated and initialised as well, (unless I return 0 back, in which case no memory was allocated)...

     

    But actually, I've noticed that the classes I put up earlier are in the middle of being changed. Notice the RayObject::CollisionHitResponse * CollisionHitData that has protected access? Notice how it has no accessor? "whoops" I was in the middle of re-designing it. Until then TestForCollision used to return a pointer (you had to declare it first, and then free it when you had finished), but I changed it to the pointer being a member instead.

     

    The new idea is that it will automatically free during ~RayObject() which hasn't been written yet. The pointer is nulled during the Initialise method and as long as it stays null, it hasn't hit anything. If it hits something it allocates and initialises the struct - normally that would end the projectile's life (at the start of the next physics tick), but if not it can go back to a null pointer (after freeing it) once it's no longer colliding.

     

    In fact, breaking news (international alert) I'm not even sure it needs to be a pointer... the NumEntitie**** field can act as the flag (zero = miss, non-zero = hit) - and if it's non-zero call realloc on the two pointers to make them large enough and then fills the data. So one less allocation when creating a RayObject (ie one less bit of cleaning up when finished :) )... Sounds like I've got quite a bit of festive coding to do...

  6. - Accessors should be const: bool IsExplosive() const;

     

    That's probably my java upbringing - we were never taught that at uni, so I just translated it directly. But now you mention it, it's so obvious... (If you're supposed to do that in Java too then I blame my uni lecturers)

     

    Initialize the variables, always!

     

    That's what the Initialise method does - all constructors call that. If there are derived classes, then L1, is for the base class's variables, L2 is for all which directly inherit from. L3 for all which inherit from that class etc (could cause confusion with multiple inheritance but right now, there is only single inheritance), since they can't have the same name without making it virtual and redefining.

     

     

    You've linked to this post there and I've never heard of virtual destructors before.

     

    - Pass complex types as const reference: const std::string& EntityConfigFileName

     

    Is this because I'm not modifying the string (which I'm not, it's read only) or is it something else? I know const means (I think) 5 different things but the only one I ever remember is immutable variable...

     

    unless you need to manage the lifetime

     

    If I took the time to design it carefully I could probably make it so that they were only in scope when not on the front menu. However, I'm lazy and find it easier (in this case) to give them global lifetime, and simply reset the list when starting to load (and unload) a level. The list shouldn't get that big from a memory point of view, but will have entries rapidly appearing and deleting many times a second.

     

    In a way I suppose I'm building it a bit like UT 99... You can be in the middle of a level, press escape and up comes your front menu (but the level is still there in the background - and in a multiplayer environment, very much alive and ticking). I'm basically building the same way, just starting with an empty level, rather than no level.

     

     

    This is whay I always say, I might be able to write a program in C++, but no way am I a pro... I've still got a lot to learn

  7. Those pointers have no owner. They are akin to bookmarks, with the struct akin to the book's pages - the book doesn't read itself (in my mind, that sort of behaviour denotes a class), instead they book is read by someone. I could set up an object to read the book, but since I'll only have one book reader object I feel it's overkill to set up a class, when a procedural interface will perform almost identically.

     

    Instead I use the visible functions to alter the list and traverse through it. They have global lifetime, but with limited scope so I'm not tempted to try and write the pointer values whenever I feel like it - as I'm sure you'd agree, doing that would be loony...

     

     

    However please don't think I'm "anti classes". For completeness, the projectile list points to a RayObject. But the RayObject's test for collision is very different based on whether it is a "hitscan" or moving "projectile". The list relies on polymorphism and virtual members to iterate through the list once rather than two lists, one for hitscans and one for projectiles. This can't be done without classes. Plus due to the sheer rate that these objects will be created and destroyed - and due to their "active" nature ("the book reading itself", or "the projectile moving itself") they're definitely suited to classes, and I wouldn't dream of trying to implement these in a procedural way.

     

    //Callback prototypes used by this class
    //The prototype for the collision test "prefilter" callback. Prefilter means a ray entered a body's AABB, should this body be accurately checked (slow) for collision, or disregarded now?
    //This can be used (for example) for a lightning beam, which starts at the firing player's origin, to stop it hitting the player that fired it. Since it would be overkill to try and ungroup that player from the players group just for the duration of the lightning beam collision check
    typedef unsigned int (* RayObjectCollisionPrefilterCallback)(const NewtonBody * body,  const NewtonCollision * collision, void * userData);
    
    //The prototype for the collision test "process hit" callback. Process hit is called for a body which was not discarded from the prefilter, and where the ray hit actual geometry (as opposed to entering the AABB, but then completely missing all faces). This allows us to figure out where the collision was in relation to the body's origin, so we can add the "throwing" force in case of explosions
    typedef dFloat (* RayObjectCollisionProces****Callback)(const NewtonBody * body, const dFloat * normal, int collisionID, void * userData, dFloat intersetParam);
    
    //A flexible and adaptable struct for when TestForCollision returns. Your own filter callback will decide if the raycast is an "all body" "closest hit" or "first hit" type. However first hit is not recommended for projectiles since there may be others closer, but with a smaller AABB
    struct CollisionHitResponse
    {
    unsigned int NumEntitie****;
    Entity * EntityHit;
    //unsigned int NumCollisionPoints; //A collision point is only saved if the entity the ray collided with is also saved, so these "count" variables will be the same, making one redundant - in this case, I chose this one.
    TVec3 * CollisionPoint;
    };
    
    //The projectile class is a ray, rather than a body. It has no NewtonBody, but may have an associated TEntity
    //The ray might be "hitscan" (living for only 1 physics tick, for example a laser beam), or it might gradually move forward (like a rocket)
    //Was renamed to RayObject almost instantly
    //class RayObject : public Entity
    class RayObject
    {
    public:
    RayObject(std::string EntityConfigFileName, std::string SceneName = "");
    virtual void TestForCollision(void) = 0;//Returns a pointer to a malloc'd CollisionHitResponse struct if a valid collision occured (remember to free it when finished), otherwise returns 0 (and nothing was malloc'd, so nothing needs freeing)
    bool RemoveThisRay(void);//After all collisions have taken place, ray objects that have collided are deleted.
    bool IsExplosive(void);
    void SetDeleteTime(void);//Adds the zombie time to the current time. Once the current time is higher than the delete time, a projectile will be deleted
    unsigned int GetDeleteTime(void);
    protected:
    bool ExplodesOnContact;
    bool LifeExpired;
    TVec3 Position;
    TVec3 Rotation;
    virtual void Move(void){return;} //Hitscans can't move so they inherit this definition and just return instantly, projectiles will redefine this member
    unsigned int ZombieTime; //How long does this projectile remain drawn once it's expired? Used to prevent the laser and lightning beams from "flickering". All projectiles and most other hitscans will set this to 0. It can only be set during a constructor, and a projectile constructor will forcibly set it to 0 without even attempting to read it from the config file
    unsigned int DeleteTime; //Once a ray has it's delete flag marked, this time will be set, once this time is reached it's deleted.
    CollisionHitResponse * CollisionHitData;
    bool HitDuringUpdate;
    void MarkForDeletion(void);
    unsigned long long ECB;
    
    //Previously these two were passed as parameters to the TestForCollision function.
    //Now they are instead set during the constructor, read from the entity config file. However, it's not possible to users to write their own callback functions. Certain strings will "map" to different callbacks - only the predefined callbacks are valid.
    //However it would allow people to create an instant hit shotgun, by using the machinegun callbacks for their shotgun - so that kind of mod-ability will still be present
    RayObjectCollisionPrefilterCallback PrefilterCallback;
    RayObjectCollisionProces****Callback Proces****Callback;
    private:
    void InitialiseL1();//Only the correct constructor can call this. Constructors for derived classes can't
    };
    
    class HitscanRay : public RayObject
    {
    public:
    HitscanRay(std::string EntityConfigFileName, std::string SceneName = "") : RayObject(EntityConfigFileName,SceneName);
    void TestForCollision(void);//Test for collision takes the possibility of limited range into account. Once finished, ray will be marked as ready for deletion. At which point once its zombie time is expired, it will be deleted
    protected:
    unsigned int Range; //Tenths of a unit, so 10 = 1 unit.
    private:
    void InitialiseL2();
    };
    
    class ProjectileRay : public RayObject
    {
    public:
    ProjectileRay(std::string EntityConfigFileName, std::string SceneName = "") : RayObject(EntityConfigFileName,SceneName);
    void TestForCollision(void);//Once finished, checks the expire team, and if expired, deletes the ray -instantly-
    protected:
    unsigned int ExpireTime; //Time after which the ray expires. The weapon which fired the ray will store the -length of time- the ray is valid for (in milliseconds), when creating the ray, it looks this up, and adds it on to the current game time. After a check for collision, the time is checked: if the life has expired then the ray will be marked as such, and deleted at the end of the physics tick
    unsigned int Speed; //Tenths of a unit per second, so 10 = 1 unit per second. Not affected physics update rate
    private:
    void InitialiseL2();
    };

     

    The pointer to base class makes it a breeze. Just tell each RayObject to TestForCollision and they will run their correctly defined version

     

    classes form the majority of my project. I think more than structs and namespaces combined... It's just static classes that have always irked me. For me now, static classes as a means of access protection is no longer necessary.

     

    I'm starting to get the idea that this secret namespace idea was much more common before Java came about than it is now. Sadly, it didn't translate directly into Java, whereas Java's workaround for it did translate directly back into C++, therefore you get more uniform code between the languages if you use the static class method. Of course I'm too young to know if that's actually true or not, but it sounds like it might hold water.

  8. The pimpl idiom looks almost identical - the only difference being the obvious: classes instead of namespaces. Thus just boiling down to each individuals preference in semantics. Certainly to me, this doesn't look any less confusing.

     

    That said, your example hasn't quite made the class MyObjectPimpl totally secret. If this was defined in a header file, then if I included the header file in an external source file, I could write:

    YourCompany::YourProject::YourLogicalNamespaces::Details::MyObjectPimpl * APimplObject = new YourCompany::YourProject::YourLogicalNamespaces::Details::MyObjectPimpl();

     

    ...and I've just got myself an instance of a class that I'm not supposed to be accessing... But I also wouldn't type this by accident :) and it's accidental mistakes I'm trying to protect against. So really, I'm just nitpicking here, it's not really a valid criticism

     

     

    But by converting the Details namespace into an unnamed namespace, it's impossible to fully qualify it from outside YourLogicalNamespaces. Thus MyObject can create instances of the pimpl, but no one else can.

     

     

    I learned about unnamed namespaces here - the second answer (which builds on the third answer)

     

    http://stackoverflow.com/questions/9321/how-do-you-create-a-static-class-in-c

  9. Well, I've just learned something too, from the comments... I thought that access specifiers were invalid for structs, and that all struct members had to be public. Apparently not...

     

     

    The advantage is probably none in terms of performance. It's just the way I like to work... I've always thought of classes as "collections", and a collection with just one thing always seemed silly to me. It's like having a shelf reserved just for trophies, and then only putting one trophy on it. I'm fine with classes having some static members, but a class with only static members never felt like a "proper" class to me. So I guess it really is just semantics...

     

    The advantage to me is that it prevents the private members from showing up in intellisense. Yes there are icons in the autocomplete list which tell you which members are public, and which are not, but I'm guilty of choosing the name that sounds right and then just tabbing it away, without actually checking if it has the right access specifier.

     

     

    And I must say, I would prefer that LEO::Draw namespaces arrangement over classes, but that's probably something unique to me. Except for maybe Images. Personally I might have made Image a class, with a Draw method. But points or lines, no way. A surface might be a class, which contains DrawPoint(), DrawLine() etc public functions though.

     

    But remember, LEO isn't just built with me in mind - really it should be the people using it, who decide if they prefer the static class or the namespace approach.

  10. Don't blame intel for the mac. Apple chose to switch to intel's new processors. No one held a gun to the figurative Apple's head.

     

     

    But hey, I've stuck with AMD since 2001. A processor that works and sold on its own merit rather than by corporate bullying, and now outright lies...

  11. Well then he just has to add a command allowing to disable integrated physics engine. This will probably be easy for Josh.

     

    Would you believe, an idea as simple as that never even occured to me... (Actually, I'm sure you would)

  12. I'm not so sure about interchangeable physics engines. Because whilst the graphics rendering all appears the same (in a black box view), physics engines deep down can be very different. Not all support buoyancy, not all support cloth effects, etc.

     

    Most physics engines are designed to be hooked up to a graphics rendering system. The example from newton that I know is that for every rigid body that was moved, a user defined callback is called. Newton gives you the body that was moved and the 4x4 matrix to represent its position, rotation and scale. Newton bodies also store a single pointer for your own use. Usually that's the graphical object which visually represents that body.

     

    So for the Leadwerks, when the callback is called:

    • Read the pointer stored with the rigid body. (When you created rigid body, you should have saved the pointer to the TModel which represents the body):
    • Transpose the matrix (Because newton gives the matrix in "row-major" by default, probably because there are more DirectX games out there)
    • Call SetEntityMatrix on the model pointed to by the pointer, with the transposed matrix.
    • Voila!

     

    Newton and Bullet probably have very different structs and classes deep down and trying to incorporate them both into the engine would be wasteful. All physics engines are designed to easily interface with any graphics renderer, because without the graphics, you simply have no idea if the physics calculations are working accurately or not. Bullet probably relies on a very similar way of getting it's positional information to a graphics renderer. If it is that simple to interface with, I would say that physics should not be integrated into LE 3 at all.

     

    Imagine the prospective companies interested in LE 3. They might have decided on a physics engine already (Or even written their own). To suddenly be told, "you've got to use one of these physics libraries - In the way that I've wrapped them up", might just turn them away.

  13. Microsoft keyboard (and mouse) on the last picture :lol: (native mac keyboard in the background). You should upload the picture to mac websites... They'd like it...

     

    Does the keyboard say "Keyboard" on the under side? We had Mac Pros at uni those ones did. They also had the word "Mouse" on the under side of the mouse. Did they really think no one would recognise what they were?

  14. Does WaitEvent() block whilst it's waiting for an event or does it just return null if nothing is waiting?

     

    If it blocks (either indefinitely or up to a maximum interval) then you'll really feel the advantage of multithreading. And in that case, you would have been better going for a quad core with lower clock speeds. Parallel computation always wins over raw speed.

     

    But it's a bit late to say that now anyway, you've already ordered the thing.

  15. After a bit of reading, I can now invert a 3x3 matrix. Apparently inverting a 4x4 is jst a matter of breaking it down into four 3x3s? Or something like that...

     

    Maths just seems to be one of those things that if you don't learn in school/college, it becomes so much harder to learn it yourself later. If i'd learned it at college, it would probably be really easy for me to do...

  16. I didn't have any issues with the A0 through D3 element numbering, I figured that bit out. My point was that a Vec16 didn't have an invert operation. At the time, I thought this was some proprietary code of Josh's that just didn't exist anywhere else.

     

     

    ...But it looks like DaDonik has solved that bit for me. The code on the highlighted site doesn't look very complicated... just long. I can live with long, so long as I know what it's trying to do.

     

    What I don't know about that code is why it works... But that's not important in maths. Maths isn't about explanations, it's about blindly following rules. Things only go wrong when you don't follow the rules correctly, or follow the wrong rules.

     

    In any case, when I get a bit of motivation back, I will try it out and hopefully carry on with the project.

  17. try/catch is not really meant for actual programming, but only for theoretical programming and teaching purposes. You should rather use checking of NULL pointers in your code, or use references.

     

    I can see the advantage of try-catch: As soon as the exception occurs, the code jumps straight to the first matching catch statement, (so the general "anything goes" catch should always be last). With if null checks, these checks are only done when you say so. The code could have gone wrong but carry on executing. If for some reason you forget the if null check, the error could go undetected until the whole programs comes crashing down.

     

    ...That said, so far I've only used if null checks in C, but in time, I probably should be moving to the try catch system

     

    I assume like Java (what I learned at uni .. my first taste of try-catches) that you can make it so that some functions must have exception checking. Either by try catch blocks, or by making the current function throw the exception up the call stack for something else to deal with.

  18. One of the most confusing parts for me was pointers versus references. In C++, pointers act pretty much like an object in Blitz3D

     

    When I realised that about a year suddenly pointer made sense. I saw that everything in Blitz3D was just a number. Armed with that new knowledge

     

    1. client-side prediction is inaccurate and wrong, 2. It was originally designed for 56k modems

     

    But still when the server has a large number of entities to track it starts to fall over. I'm generally of the opinion that clients are always dishonest and the server should authoritatively do as much as it can, there are some things that you have to offload to clients, debris for example.

     

    Whilst we have a much higher data rate than we did 10 years ago, we also expect our games to handle a much larger load than they did at that time. One of my brothers' final year uni project was to build a small multiplayer game in Blitz 3D. Although he promised client side prediction, it wasn't there for the final submission. On a local subnet it was fine, and this was still so when played on the wider local network. As soon as it hit the Internet you could see occasional stutters.

     

    That told us that a relatively high end home connection (20 megabit cable) connecting to a server on the SuperJanet network still needed a little bit of prediction to make it as smooth as it was on lans. And If you're wondering, SuperJanet has a throughput rate of about 40 gigabits per second, it's certainly one of the fastest private networks in this country, if not one of the fastest world. I'm sure there are some that handle terabits per second, but no one here is going to get their game hosted on one. But that certainly make me wonder about no prediction coupled with the much lower throughput rate of most dedicated server providers.

     

    I did not like the direction Microsoft went with Windows 7, and the new OS has finally put me in a place where I am willing to try something new.

     

    Oh come on Josh, you there was another option... :)

    I can see why you might be annoyed having paid so much for 7 Ultimate...

    ...But paying even more for a mac is not the way :)

×
×
  • Create New...