I did commit to dropping the thread properties editing functionality. It was being strange and difficult to work on, so it simply will not be a thing. Instead, I moved ACL control to its own page, which will be accessible from a moderator control panel in the thread. I did a little bit of checking around the database and determined that it's best to simply try to occupy permission ID #1 first and if it's taken, use the maximum plus one. Eventually, the table will waste lots of IDs, but I'm thinking of implementing a "pack database" button for administrators. The thread ACL control works very nicely. Tick the boxes next to an ACL entry to remove it and type a name in the text box under the list to add it.
Various technical articles, IT-related tutorials, software information, and development journals
Sunday, September 29, 2013
Friday, September 27, 2013
Minecraft - Water Destroys End Portals
I recently and accidentally discovered that pouring a bucket of water onto the side of a block occupied by an End portal will destroy that part of the portal. Fortunately, only source blocks can do this, but it was very terrifying to see one ninth of my access to the End erased. I filed a bug report on Mojira, which will have the latest on this issue.
Thursday, September 26, 2013
Logofrag - Abandon Edit Ship
Debugging the edit-thread functionality has become infuriating. As such, I have decided to split it into its own page, possibly dropping support for all attributes except ACLs. It doesn't really make sense to allow people to write exceedingly long fragments after the thread had already been going with short ones. Modifying the permissions will have to be possible. Once this is finally out of the way, I can develop useful things like thread view, fragment adding, and user profile pages.
Wednesday, September 25, 2013
Logofrag - Edit Rage
I did even more head pounding and determined that the approach I created last post is not useful in Logofrag. I have tried tons of ways over the past three days to allow thread properties to be edited by the moderators, but it won't work properly. I just now got it back to a state in which thread creation works and made editing not crash the server. Editing does, however, duplicate the ACL entries and has no effect on other properties. I am getting very frustrated with this project, but I'm sure it will only take another day or two before I break past this issue and actually start doing things.
Tuesday, September 24, 2013
LINQ - Get First Unused ID
I just spent two hours pounding my head against the proverbial wall trying to get some Logofrag stuff to work correctly. After messing around with all manner of methods, I found an amazing StackOverflow answer that put all the pieces in place. This is how I finally was able to find the first unused permission ID:
Dim idsQuery = From right In data.ThreadRights Select right.RightID
Return (From n In idsQuery Where (Not idList.Select(Function(x) x).Contains(n + 1)) Order By n Select n + 1).First
I had never before used lambdas, so that's another thing I learned. They're very easy, just say whether it's a function or sub, give the arguments it takes, and write the return value.
Dim idsQuery = From right In data.ThreadRights Select right.RightID
Return (From n In idsQuery Where (Not idList.Select(Function(x) x).Contains(n + 1)) Order By n Select n + 1).First
I had never before used lambdas, so that's another thing I learned. They're very easy, just say whether it's a function or sub, give the arguments it takes, and write the return value.
Monday, September 23, 2013
Keep Calm and Resume Next
No, please never actually write "On Error Resume Next." But do enjoy this parody I made of the "Keep Calm and Carry On" posters!
Don't you love QuickBasic?
Don't you love QuickBasic?
Sunday, September 22, 2013
Logofrag - Threads
LINQ/SQL is more of a pain that I had originally thought. It requires me to figure out the next available primary key and won't allow me to access foreign key relationships as collections without them. I did manage to slog through coding-behind the thread moderator interface. Users can now create new threads and possibly reopen the properties of old ones (I haven't tested that yet). After repairing all the database things, I added a "permission denied" page that is shown when users attempt to use query string manipulation to access things they can't.
Saturday, September 21, 2013
Visual Basic .NET - Binary Operations
In Visual Basic, I sometimes start missing Java's nice bit operators, especially when I really need to pack boolean data into a single number. Fortunately, VB has this; it's just less intuitive. The operator for logical functions is indistinguishable from that of bit functions. So, I can just do this:
For x = 0 To 7
ChecklistPunctuation.Items(x).Selected = ((t.Punctuation And 2 ^ x) <> 0)
Next
Less fortunately, VB does not have shift operators. You can however make do with integer division, multiplication, and exponents of two. To shift a collection of bits N to the left, do this:
shifted = (bitcol \ (2 ^ N))
Maybe it's true that the language wasn't intended to be used in advanced/professional environments, but it certainly has been tortured into providing pretty much any functionality you could want.
For x = 0 To 7
ChecklistPunctuation.Items(x).Selected = ((t.Punctuation And 2 ^ x) <> 0)
Next
Less fortunately, VB does not have shift operators. You can however make do with integer division, multiplication, and exponents of two. To shift a collection of bits N to the left, do this:
shifted = (bitcol \ (2 ^ N))
Maybe it's true that the language wasn't intended to be used in advanced/professional environments, but it certainly has been tortured into providing pretty much any functionality you could want.
Friday, September 20, 2013
Logofrag - Index and Creation
Logofrag development is going along very easily! I like these kind of projects because there's not going to be any bang-head-against-wall frustration, but it will be an interesting challenge to complete. Today, I wrote the code-behind to create a table of threads sorted by time updated, 50 per page. I've actually never done anything with pages before, but it was pretty easy. I also started the front-end of the page to create a new thread, which is one of the essential functions. The database is being changed as I create pages -- the ability of Visual Studio to drop and recreate tables while making it seem like a normal change is amazing.
Thursday, September 19, 2013
Do not Suspend or Abort Threads
Jim Mischel recently published an article called "Do not suspend or abort threads." He's a really good programmer, but his blog doesn't seem to be too popular, so I figured I'd give him a few more views! Also, drowning in schoolwork.
Tuesday, September 17, 2013
LINQ Does Not Compile
Today I learned that LINQ to SQL statements are not compiled as normal .NET code is. Instead, it's somehow transformed into a normal SQL statement by finding a comparator that operates on the conditions you gave and checking to see if it has the right argument types. So, don't just go and write any boolean-producing expression as the Where part of a query; it's better to collect all the parts of it in a line before and use simple variables instead. Remember, the SQL server isn't passing every data row back to your query for inspection; LINQ just writes all the fancy query stuff for you.
Monday, September 16, 2013
Logofrag - The Database
Since I have a lot of schoolwork, Logofrag won't get developed very quickly. However, I have created the database - using SQL this time. I learned my lesson about custom data formats for web applications; they are way more of a hassle than they're worth. LINQ is going to make it amazingly easy to manipulate user data inside the strange world of SQL. Besides getting the database ready, I also prepared the master page that will provide the consistent style across the site. I'm going for a clean, streamlined, old-school look.
Sunday, September 15, 2013
.NET Repair Kit
Eventually, your .NET Framework installation will need updating. .NET updates, especially those security-critical ones, have been known to endlessly fail and get stuck in the Windows Update queue. This happened to a computer I was working on today, so I looked up how to fix the problem. I found a very helpful post on Microsoft Answers that contained a link to a collection of utilities that fixes the problem. It does so by completely uninstalling all versions of the Framework, then reinstalling them. I put those four programs into one ZIP archive, which I recommend you keep on hand in case this problem happens to you.
Saturday, September 14, 2013
Introducing Logofrag!
I've seen the three-word story game (you know, the game where each person extends the collaborative story by three words?) played on multiple online forums. Every time, someone misunderstands the English language (or intentionally messes up the structure) and, since the forum's admins aren't responsible for the content of those posts, the people actually wanting to advance the story have a problem.
So, I'd like to use my knowledge of ASP .NET to create a website just for this game! I'd like to name it "Logofrag" because everyone contributes a fragment of the the logos. People could start different stories with different subjects and rules -- and then moderate their own threads! Since different people might have different ideas of what counts as a word, how many people must post between two posts of the same person, and other things, there would have to be many options for everyone to get what they want. It seems pretty simple and I'm willing to dedicate a tiny slice of my free time to creating this.
So, I'd like to use my knowledge of ASP .NET to create a website just for this game! I'd like to name it "Logofrag" because everyone contributes a fragment of the the logos. People could start different stories with different subjects and rules -- and then moderate their own threads! Since different people might have different ideas of what counts as a word, how many people must post between two posts of the same person, and other things, there would have to be many options for everyone to get what they want. It seems pretty simple and I'm willing to dedicate a tiny slice of my free time to creating this.
Thursday, September 12, 2013
Do Not Use - Blackbaud (NetClassroom)
New series time! In "Do Not Use", I will talk about applications that should not be considered when setting up a new system. This time, it's Blackbaud, also known as NetClassroom. Blackbaud is a school management system, so its purpose is to keep track of student grades, assignments, attendance, and other school stuff that only teachers need to worry about. It does keep track of those things fine, but its interface is just not good. Turning in an assignment is painful; it requires going through a menu with "Advanced" in the title and other steps. The authentication system seems to have some sort of problem: the program has forgotten my password at least two times now. Yes, I am certain I remember it. Yes, I am certain I am typing it correctly. Blackbaud forgets user passwords. In addition to that, it throws some sort of COM error when I try to log in with Chrome on my home computer. It's impossible to upload files from a Mac because it requires the client to use a Windows common dialog. Submission of files is done through a strange pop-up window that forces you to navigate through a variety of classification levels before letting you even see the list of things eligible to be turned in. The teachers also report annoyances with it, which I haven't seen in person but I believe. Please spare your students and teachers a major hassle and use something like Canvas, Blackboard, Moodle, or even Focus for your SIS.
Wednesday, September 11, 2013
Reading from Streams
Instead of trying to passionately comment on the 9/11 attack, I'll leave that to everyone else and do my normal thing.
I've recently been curious about streams in .NET and why the documentation on it is so terrifying. Since Jim Mischel did an article on it just today, I'll hand it over to him. (I'm busy with schoolwork and very very tired.) Mr. Mischel is amazing, go read his article and follow his blog.
I've recently been curious about streams in .NET and why the documentation on it is so terrifying. Since Jim Mischel did an article on it just today, I'll hand it over to him. (I'm busy with schoolwork and very very tired.) Mr. Mischel is amazing, go read his article and follow his blog.
Monday, September 9, 2013
Quark - Browser with a Formally Verified Kernel
Everyone knows that the Internet can be a terrible place. Hackers, phishers, and general baddies lurk around every proverbial corner. Some incredibly smart people at the University of California have created a web browser based on Google Chrome whose core is formally proven (using mind-blowingly advanced theorems and logicy stuff) to be secure. Different tabs cannot interfere with each other, the address bar cannot be hijacked, and no files will be placed on your computer without your consent. This browser is called Quark. It's still in experimental stages, but it has been tested on advanced web sites such as Facebook. Currently, you can download its source code or read about all the logic. Guess which blogger will be using Quark soon.
Friday, September 6, 2013
Forge - Correct Use of ResourceLocation
After Minecraft updated to version 1.6, Forge did some changes to the GUI texture loading. Thankfully, it's considerably easier to bundle all manner of resources, but unfortunately more complicated to set up the addresses. They reverted bindTexture to func_110577_a and changed its argument to a ResourceLocation instance. Such an instance can be easily created with one or two strings. Important note: You should use only the one-string constructor; the two-string one will only work when launching from Eclipse. That string is of the format "modname:textures/gui/filename.png". So, for my Absorber, I would create the ResourceLocation like so: "new ResourceLocation("higherpower:textures/gui/absorber.png)". Notice that the mod ID is now required to be in all lowercase. While developing, place your mod's assets folder under the src folder.
Wednesday, September 4, 2013
HigherPower - Improving /genhere
After noticing the setRandomHeight method of the StructureStart class, I decided to look into it. It appears to be the way normal Minecraft provides variation in the height of Nether fortresses, strongholds, and abandoned mineshafts. I used the location of the command sender to make the structure generate at a similar Y level to the player. It has the unfortunate side effect of making villages fail to generate, which I will fix somehow sometime.
Tuesday, September 3, 2013
Forge - Sync Progress Bars
At the time you read this, I'll be thoroughly enjoying myself in a camp in northern Wisconsin. Enjoy this scheduled post!
Synchronizing GUI progress bars between server and client may seem complicated at first, but it's actually very simple. If you've set up a GUI renderer and container already, you're ready for this tutorial.
First, make sure the client-side tile entity isn't doing anything with progress bars besides having a variable for it. Open up the container class and create some variables for the previous state of all the progress bars (like burn time and cooking progress). Let's use ContainerFurnace to explain stuff.
public void addCraftingToCrafters(ICrafting par1ICrafting)
{
super.addCraftingToCrafters(par1ICrafting);
par1ICrafting.sendProgressBarUpdate(this, 0, this.furnace.furnaceCookTime);
par1ICrafting.sendProgressBarUpdate(this, 1, this.furnace.furnaceBurnTime);
par1ICrafting.sendProgressBarUpdate(this, 2, this.furnace.currentItemBurnTime);
}
The super call is necessary to sync inventory; the sendProgressBarUpdate calls are more interesting. This is where the server tells the client what it knows about the GUI. The numbers (0, 1, 2) are IDs of the progress bars and the final argument is the value of the progress bar as an integer (taken from the represented tile entity).
public void detectAndSendChanges()
{
super.detectAndSendChanges();
for (int i = 0; i < this.crafters.size(); ++i)
{
ICrafting icrafting = (ICrafting)this.crafters.get(i);
if (this.lastCookTime != this.furnace.furnaceCookTime)
{
icrafting.sendProgressBarUpdate(this, 0, this.furnace.furnaceCookTime);
}
if (this.lastBurnTime != this.furnace.furnaceBurnTime)
{
icrafting.sendProgressBarUpdate(this, 1, this.furnace.furnaceBurnTime);
}
if (this.lastItemBurnTime != this.furnace.currentItemBurnTime)
{
icrafting.sendProgressBarUpdate(this, 2, this.furnace.currentItemBurnTime);
}
}
this.lastCookTime = this.furnace.furnaceCookTime;
this.lastBurnTime = this.furnace.furnaceBurnTime;
this.lastItemBurnTime = this.furnace.currentItemBurnTime;
}
The loop iterates through all the crafters (the players viewing this container) and sends an update on any progress bars that have changed. The calls are exactly the same as in addCraftingToCrafters. After informing all the crafters, it updates its cache of the progress bar states from the tile entity.
@SideOnly(Side.CLIENT)
public void updateProgressBar(int par1, int par2)
{
if (par1 == 0)
{
this.furnace.furnaceCookTime = par2;
}
if (par1 == 1)
{
this.furnace.furnaceBurnTime = par2;
}
if (par1 == 2)
{
this.furnace.currentItemBurnTime = par2;
}
}
This is where the client fixes its progress bars. It receives the ID of the bar to update and the value. With that, it decides which tile entity variable to set.
So there you go! The GUI class does not need to be changed, it will reflect the tile entity's opinion on the progress bars, which is now in sync with the server.
Synchronizing GUI progress bars between server and client may seem complicated at first, but it's actually very simple. If you've set up a GUI renderer and container already, you're ready for this tutorial.
First, make sure the client-side tile entity isn't doing anything with progress bars besides having a variable for it. Open up the container class and create some variables for the previous state of all the progress bars (like burn time and cooking progress). Let's use ContainerFurnace to explain stuff.
public void addCraftingToCrafters(ICrafting par1ICrafting)
{
super.addCraftingToCrafters(par1ICrafting);
par1ICrafting.sendProgressBarUpdate(this, 0, this.furnace.furnaceCookTime);
par1ICrafting.sendProgressBarUpdate(this, 1, this.furnace.furnaceBurnTime);
par1ICrafting.sendProgressBarUpdate(this, 2, this.furnace.currentItemBurnTime);
}
The super call is necessary to sync inventory; the sendProgressBarUpdate calls are more interesting. This is where the server tells the client what it knows about the GUI. The numbers (0, 1, 2) are IDs of the progress bars and the final argument is the value of the progress bar as an integer (taken from the represented tile entity).
public void detectAndSendChanges()
{
super.detectAndSendChanges();
for (int i = 0; i < this.crafters.size(); ++i)
{
ICrafting icrafting = (ICrafting)this.crafters.get(i);
if (this.lastCookTime != this.furnace.furnaceCookTime)
{
icrafting.sendProgressBarUpdate(this, 0, this.furnace.furnaceCookTime);
}
if (this.lastBurnTime != this.furnace.furnaceBurnTime)
{
icrafting.sendProgressBarUpdate(this, 1, this.furnace.furnaceBurnTime);
}
if (this.lastItemBurnTime != this.furnace.currentItemBurnTime)
{
icrafting.sendProgressBarUpdate(this, 2, this.furnace.currentItemBurnTime);
}
}
this.lastCookTime = this.furnace.furnaceCookTime;
this.lastBurnTime = this.furnace.furnaceBurnTime;
this.lastItemBurnTime = this.furnace.currentItemBurnTime;
}
The loop iterates through all the crafters (the players viewing this container) and sends an update on any progress bars that have changed. The calls are exactly the same as in addCraftingToCrafters. After informing all the crafters, it updates its cache of the progress bar states from the tile entity.
@SideOnly(Side.CLIENT)
public void updateProgressBar(int par1, int par2)
{
if (par1 == 0)
{
this.furnace.furnaceCookTime = par2;
}
if (par1 == 1)
{
this.furnace.furnaceBurnTime = par2;
}
if (par1 == 2)
{
this.furnace.currentItemBurnTime = par2;
}
}
This is where the client fixes its progress bars. It receives the ID of the bar to update and the value. With that, it decides which tile entity variable to set.
So there you go! The GUI class does not need to be changed, it will reflect the tile entity's opinion on the progress bars, which is now in sync with the server.
Monday, September 2, 2013
HigherPower - Fixed Packet Switch
I gave the Configurable Switch's tile entity function today. It just iterates through the four sides, checks the state, and if it is an output face the incoming packet is sent there. I also wrote up the Technical Manual documentation for it.
I'm kind of disappointed about the inability to control all the sides, but I might give the top and bottom states a hard-wired function.
I'm kind of disappointed about the inability to control all the sides, but I might give the top and bottom states a hard-wired function.
Sunday, September 1, 2013
HigherPower - Fixed /genhere
I decided to finally fix the inability of HigherPower's /genhere to generate villages and scattered features. It was pretty easy to do once I noticed the reason for its failure: MapGenVillage's getStructureStart calls a constructor with worldObj, which is not specified in its own constructor. All I had to do was add a little more reflection to set that to the command sender's world.
This is the result of spamming "/genhere village" with some temples mixed in:
This is the result of spamming "/genhere village" with some temples mixed in:
Subscribe to:
Posts (Atom)