Wait. What? RSS

Archive

Apr
25th
Thu
permalink

MCP Analytics II

Upon reading the last post again, I realized that I forgot to explain some technical details.

What do you, as mod-developer, have to do to use the service?

You need to sign up on the website and register your mod. Everymod will be assigned a random key, you will need to drop this key in your jar file (or decorate a class in your mod with an attribute that holds the key).

What exactly is going to happen when the gam crashes?

The mod will collect the information you see in the crash panel along with a list of all installed mods.

Who can see the crash reports?

Only you and the developer of the mods that were somehow involved in the crash (appear in the stacktrace).
How does the website know it is you who sent the report? Well, that’s only going to work if mojang implements openid/oauth for mojang accounts…

I hope that clears some of the confusion the last post created :)

If you have any questions, you know where to find me!

submit to reddit
Comments
Apr
22nd
Mon
permalink

MCP Analytics (working title)

I’ve been hinting, talking about this before and I initially had the urge to make this mod over two years ago.

What is it?

I want to automatically collect crash-reports from users for mod developers.
Why? Because we as humans are lazy. Even as developer myself, knowing the importance of bugreports, I have to actively force myself to submit bug-reports.

If noone reports a bug, it doesn’t exist. At least from the developers point of view.

Why would someone install the mod?

Bugs suck.

Granted, this is going to be a service only geared to developers, but everyone will profit form it in the end - with better quality mods.

How can you help?

Join me in making the mod! :)

Hop on irc, join #mcp-analytics@irc.esper.netthere’s a Trello board setup, there’s a repository on github and I’m going to open up my eclipse workspace using Saros for some realtime multi-user editing-fun.

So, if you fell like it, open the board, read the description, join, pick a feature to work on, fork the repo and when you are done submit a pull request!

What I want

For now all I want is being able to collect the exceptions and have them ready to send to a webserver.

Speaking of which, the webserver part will be what I’m going to focus on.

I hope I can have a test-service up and running soon.

submit to reddit
Comments
Sep
6th
Thu
permalink

Techne Online - future plans

As I was sitting in this awefully long flight from Amsterdam to San Francisco, I had some time to think about what my next steps with techne online are going to be.

First thing I’ll do will be to add a page that displays all submissions at once. I thought techne online should be like pastebin where you share links to your things, but it seems to me now that more discoverability is a good thing.

So, here’s what’s going to happen, first I’ll fiy some bugs I’ve been made aware of. Once that’s done I’ll add and allow registration, through openID or optionally a techne online account.
With that in place, you will have a profile-page that lists all your submissions - there’s also going to be a global gallery with all models. I realize that not everyone of you would want his/her model to be shared with everyone, so there will be privacy settings as well.
Options are going to be:

  • listed - viewable by everyone
  • unlisted - those with links can access it
  • private - only you have access

Additionally you can choose to allow the download of the original tcn file.

At this point I plan to add comments, ratings as well as counter (downloads, views). Note that I’m not entirely sure about that yet, it might be counter productive.

I’m also thinking about model-revisions, so you can upload an updated version of your model.

Some other things I’ve thought about and aren’t directly related to techne online, but will affect the website or its functions somehow.
I hope to be able to create screenshots of models automatically, so there can be a preview - preferably so that you can embed them in your mod’s website/forum thread. Integration into Techne itself, think “cloud” storage and embedded sharing. Make techne online the website to download Techne.

Now it’s time to start a new day in SF :)

submit to reddit
Comments
Sep
3rd
Mon
permalink

Techne Online Gallery

Techne Online Gallery

I’ve been away too long…

I spent the past few days programming, something I haven’t done in a long time and it felt great :)

I didn’t want to work on the decompiler because that would have been more “work” than fun, so I decided to bring Techne Online, which I started in January ( https://www.youtube.com/watch?v=qGLZhxH-G3E ) online.

I haven’t implemented the controls just yet because I want rendering and the backing infrastructure done first.

A short rundown of what I’m using:

  • IIS7.5 on Windows Server 2008R2
  • asp.net mvc4 on .net 4.5
  • Sql CE is used as database (only temporary)
  • Entity Framework5 as ORM
  • Techne’s javascript was written in CoffeeScript
  • THREE.js as 3D library
What’s on my roadmap:
  • Texturesupport (I only need to implement it the javascript)
  • Comments/ratings
  • Auto-screenshots
  • Embedable screenshots
  • User login/registration
  • Techne integration
  • Controls to make it a fully featured alternative to Techne
  • Animation support (*cough cough*)
I’ll post a more complete rundown and explanation after I’m back from my trip, got to go packing :)

In the meantime, happy uploading and check out: http://techne.zeux.me/139

submit to reddit
Comments
Apr
12th
Thu
permalink

When types Meet()

/// <summary>
/// Finds common ancestors in class-hierarchy.
/// </summary>
public TypeSignature Meet(TypeSignature typeA, TypeSignature typeB)


I have been tasked to write this method for the decompiler we are working on. I think the implementation is rather straight forward and simple. So, why write about it then? I wanted to share more things that are going on and update you on the progress we make.

Now, imagine we are trying to decompile a jar with the following types:
Class hierarchy
click for fullsize


When we want to meet “Clio” and “Megane”, clearly, the best type to return is “Renault”. Meeting “Phaeton” and “Renault” will give us “Car”. But things aren’t always as clear; say we meet “BarChild” and “FooTwo”, what would be the best result? The answer is, we don’t know yet and return a meta-type that contains “IFoo” and “Bar”. Later down the line we will meet this type with “FooOne” and realize that the best thing to do would be to use “IFoo”.

I’ll stick with “FooTwo” and “BarChild” as the types to meet to show how to do this programmatically.
The first thing to do is building up a class-hierarchy from the bottom up for both types.

Ancestors of BarChildAncestors of FooTwo
After that is done, I get rid of every relationship between the nodes and only group them by level represented by a

List<HashSet<string>>

.
We don’t care who’s who’s parent; the only thing we want is to find common ancestors and that’s simple now, we iterate over both lists and one set and check if we have a match anywhere.
Done.

I hope this was at least a little bit use- and insightful.
So long.

For completeness-sake, the Match method:

internal IEnumerable<string> Match(ClassHierarchyNode other)
{
    var typeBList = other.Condense();
    var typeAList = this.Condense();
    bool found = false;
 
    foreach (var item in typeBList)
        foreach (var check in typeAList)
        {
            foreach (var node in item)
            {
               var contains = check.Contains(node);

               if (!found && contains)
                   found = contains;

                if (contains)
                    yield return node;
            }

            if (found)
                yield break;
        }
}
submit to reddit
Comments
Mar
8th
Thu
permalink

Raspberry Pi

I can’t help but not get excited to get one.

I tried to stay out avoid it, but it’s too good of a plaything.

I’ve owned an NSLU2 (pretty much the previous generation’s rpi) and didn’t use it as much as I hoped. I guess the hardware was too limited after all. And it was way more expensive, so I couldn’t just buy more than one. Either way, if you are thinking about buying an rpi, head over to http://www.nslu2-linux.org/ and browse for a little while (pretty much the first 6 links in “General”), I’m sure you’ll find ideas you want to do :)

What would I do with it?

Maybe fulfill my lifelong dream of a weather-station in the bathroom. It would pretty much be an lcd behind a one-way-mirror with a custom frontend that displays a forecast and the current temperature. I would have loved to do it in wpf, but I guess that’s out of the question (too bad mono doesn’t support it). It also looks like I can’t use Moonlight either. That basically means I’ll have to opt for Qt as UI-framework.

So that’s one rpi down, I’m pretty sure I’m going to install xbmc on another one to use as streaming client so I don’t have to have my pc turned on when watching tv-shows (got IPTV via UDP-multicast, just need an IGMP-proxy…).

Other than that, there’s loads of things I want to do in various degrees of desire to actually realize it.

Just wanted to get this out.

submit to reddit
Comments
Jan
13th
Fri
permalink

Minecraft Modeling, Pieces and Subparts - Part 3 of x

This is the third post in this series of posts on 

Sub-/Childparts are grouped in what I call “piece” in Techne.

The most important part to remember is that you create ModelRenderer instances differently.

Let’s look at the dragon’s constructor:

public ModelDragon(float var1)
{
      this.texWidth = 256;
      this.texHeight = 256;

      this.setTextureOffset("rearleg.main", 0, 0);
      this.setTextureOffset("rearfoot.main", 112, 0);
      this.setTextureOffset("rearlegtip.main", 196, 0);

      this.rearLeg = new ModelPart(this, "rearleg");
      this.rearLeg.setPos(-16.0F, 16.0F, 42.0F);
      this.rearLeg.addBox("main", -8.0F, -4.0F, -8.0F, 16, 32, 16);

      this.rearLegTip = new ModelPart(this, "rearlegtip");
      this.rearLegTip.setPos(0.0F, 32.0F, -4.0F);
      this.rearLegTip.addBox("main", -6.0F, -2.0F, 0.0F, 12, 32, 12);

      this.rearFoot = new ModelPart(this, "rearfoot");
      this.rearFoot.setPos(0.0F, 31.0F, 4.0F);
      this.rearFoot.addBox("main", -9.0F, 0.0F, -20.0F, 18, 6, 24);

      this.rearLeg.addChild(this.rearLegTip);
      this.rearLegTip.addChild(this.rearFoot);
}

TextureWidth and TextureHeight should be fairly obvious.
Now, setMapTex is a different matter - it obviously takes a string and two ints as parameters. The string can be understood as path to the box the entry is referring to. It’s not the full path, it’s “PieceName.BoxName”.
The integers are nothing other than the textureOffset, it is what used to be in the ModelRender’s constructor.

public ModelRenderer(ModelBase var1, String var2)

The only reason we need to pass the instance of the model itself is to get the textureoffset, the string is the name of the piece.

To add boxes, you call addBox, like you did previously. The arguments haven’t changed, so there is no point in explaining it again.
However, what you can do is add multiple boxes to one piece. All boxes that belong to a piece share the same textureOffset, rotation and position (anchor-point).

All you need to do to create a piece hierarchy is to call addChild with the chield-piece you want to add.

Here’s an overview of how the leg-hiearchy looks.

I wanted to write about the rendering of pieces as well, but I think it should go in its own post.

And for your pleasure, the complete dragon:

submit to reddit
Comments
Jan
7th
Sat
permalink

MCP-48h

I wasn’t around when the idea was born, but I know that none of us had the time to participate in LD22. Anyway, we are holding our own (private) competition.

The theme is “Supernatural & Parallel Universe”, there’s no set language to use and the only rule is that you have to make everything yourself.

I wasn’t sure if I wanted to participate because I have many RL things to do, don’t feel like programming at the moment - haven’t been for three weeks now - and have many other projects I’d like to have seen finished first.

Well, I thought I could combine a project and this competition - I present

Techne online! I have an idea how to make a game out of it, let’s see if I even get the basic functionality for it in before the time runs out ^^
I hope that will save me from countless “oooh, me need mac version - you sucks”-comments in the future.

This is what I have atm, you have an ugly stone block (damn you “make it yourself” rule) which will have a proper mc-texture when it’s over.

Current Progress

I will try to update the gallery regularly.

submit to reddit
Comments
Dec
20th
Tue
permalink

HI there,

the next blog-post in my series will take longer.

I haven’t been able to work on anything due to personal reasons I don’t want to go into. And I’ll be spending a lot of time with my family in the holidays, so I wont be able to work on much either (even if I could bring myself to do something)

I hope you understand.

submit to reddit
Comments
Dec
13th
Tue
permalink

Minecraft Modeling, Animation - Part 2 of x

In this series I try to tackle topics about modeling in Minecraft, each article will build up on the previous ones - so if this is the first time you visit, you may want to read the previous posts as well.

This time I’m going to talk about the setRoationAngles-method and its parameters.
I already gave a peak in last week’s post but only superficially (and partially wrong :/ )

I’ll repost the code to refresh your memory:

    @Override
    public void render(Entity entity, float var1, float var2, float var3, float var4, float var5, float var6)
    {
        setRotationAngles(var1, var2, var3, var4, var5, var6);
        body.render(var6);
    }

    @Override
    public void setRotationAngles(float var1, float var2, float var3, float var4, float var5, float var6)
    {

    }

Think of the walk animation as a function, a cosine function to be exact.

Where y(x) is the rotation in radians at t(x).

I’ll use ModelChicken as an example - it’s decompiled with ff and mcp:


leg0.rotationX = MathHelper.cos(var1 * 0.6662F) * 1.4F * var2;
leg1.rotationX = MathHelper.cos(var1 * 0.6662F + 3.1415927F) * 1.4F * var2;

setRotationAngles arguments

1st and 2nd argument

This means that var1 is used for time and var2 modifies the amplitude. And this makes sense, the faster a mob walks, the more/higher their legs move. So I think it’s safe to call var1 “time” and var2 “walkSpeed”.

Let’s look at the next graph.

Now guess how this would look if it was applied to rotationX of a leg ( y(time) = cos(time) * walkspeed )

This could describe a mod that stands still, begins to walk, reaches a max speed (of 1) and gradually slows down again.

How are the values calculated?

The magic happens in RenderLiving.render(Entity entity, double var2, double var4, double var6, float var8, float var9):

float time = mob.field_703_S - mob.field_704_R * (1 - var6);
float walkSpeed = mob.field_705_Q + (mob.field_704_R - mob.field_705_Q) * var6;

3rd argument

I’m not really sure how to name var3, it’s being used for three different purposes and the calculation of it is up to the renderer-file.

  • Wolf: angle for its tail
  • Squid: angle for the tentacles
  • Chicken: angle for the wings

So, it’s basically up to you what this is, all you need to do is override handleRotationFloat in the renderfile.

And it’s pretty much up to you how you do that as well, the Wolf just gets the tail angle, while squid and chicken calculate it.

Squid:

protected float handleRotationFloat(EntitySquid entitysquid, float f)
{
  //f == Timer.renderPartialTicks and represents the passed ticks since  the last rendercall (0.0 - 1.0), it gets passed down from runGameLoop() in  Minecraft.java.
  return entitysquid.lastTentacleAngle + (entitysquid.tentacleAngle - entitysquid.lastTentacleAngle) * f;
}

Since lastTentacleAngle and tentacleAngle get set in onLivingUpdate which is only called 20 times per second, we need to tween between angles to make sure we get a fluid animation and this is done here.

4th and 5th argument

They are rotationYaw and rotationPitch respectively, tweened like in handleRotationFloat. In RenderLiving:

float rotationYaw = entityliving.prevRotationYaw + (entityliving.rotationYaw - entityliving.prevRotationYaw) * f1;
float rotationPitch = entityliving.prevRotationPitch + (entityliving.rotationPitch - entityliving.prevRotationPitch) * f1;

You use them to determine where your model should look, think of it as headRotationX and headRotationY and this is how it’s being used as well. In your model-class:

head.rotateAngleY = f3 / 57.29578F;
head.rotateAngleX = f4 / 57.29578F;

You might wonder why you divide by 57.29578, answer is simple, rotationYaw/rotationPitch  are in degrees and must be converted to radians before assigning it to rotateAngleX/Y :)

6th argument

This amounts to scale, but you normally don’t have to mess with it, you just pass it to the render-method of you ModelRender.
It’s set to

float scale = 1 / 16.0f;

in code, remember 1 block is 16x16 pixels in texturesize.

Summary

To sum up, arguments passed to .setRotationAngeles are

  1. time for the walk animation
  2. speed for the walk animation
  3. unsure how to name it, use is pretty much up to you
  4. rotationYaw
  5. rotationPitch
  6. scale

I hope this helps you understand how animations are done :)
This post focuses on the setRotationAngles-method on purpose, we need that knowledge for later posts - if you have questions about something that goes deeper than what I wrote leave a comment and I might just write another article answering it :)

Next up: EnderDragon explained

submit to reddit
Comments