Error with Spine Atlas file - cocos2d-x-2.x

i'm using cocos2d-x 2.2.3 and spine 1.9.07.
I've exported "seller.atlas", "seller.json" and "seller.png" by Spine and put them in Resource folder of my project. Then, in init() method I add these code to use skeleton animation
skeletonNode = CCSkeletonAnimation::createWithFile("spine/seller.json", "spine/seller.atlas");
skeletonNode->debugSlots = true;
skeletonNode->timeScale = 0.5f;
skeletonNode->setAnimation("walk", true);
skeletonNode->debugBones = true;
CCSize windowSize = CCDirector::sharedDirector()->getWinSize();
skeletonNode->setPosition(ccp(windowSize.width / 2, 50));
addChild(skeletonNode);
but It throws out an error like this
void CCObject::release(void)
{
CCAssert(m_uReference > 0, "reference count should greater than 0");
--m_uReference;
if (m_uReference == 0)
{
delete this;
}
}
It means that skeletonNode is NULL so it must be something wrong with the atlas file.
But I don't know what wrong is it :(
Any help would be appreciated! :D

It's because cocos2dx 2.2.3 is using an old spine parser. Spine 1.9 generates atlas files in a different format. there is an extra line of "size: xxx,xxx".
To address this specific problem, add
readLine(0, end, &str);
in Atlas.cpp
before
if (!readValue(end, &str)) return abortAtlas(self);
Note you might run into other problems such as unknown attachment type mesh/skinned mesh since Spine 1.9 using new format. You need to update spine code in 2.2.3 to fix all.

Related

Adding # to formula after =

When I add the formula FORECAST.ETS, it adds an # after the equal symbol, like this: = #FORECAST.ETS. Why is this happening?
The code snippet is:
ws.cell(column=1, row=2, value="=FORECAST.ETS(...)"
When I open it with Excel (latest Office 365 version), it shows as =#FORECAST.ETS(..)
I have hit the same issue, but not with Python and openpyxl, but with dotnet Core C# and EPPLUS. What follows is perhaps a workaround based on my findings... but not ideal. I suspect it will work with openpyxl too.
Re-creating the problem
I have written a simplified C# console app that firstly creates a new XLSX (foo.xlsx), writes out some data and my formula, and then outputs the cell with the formula and the value to the Console. It then saves and closes the XLSX, and reopens it and again outputs the formula cell and its value. The code is as follows:
using OfficeOpenXml;
using System;
using System.IO;
namespace TestFormula
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Test starts");
ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
if (File.Exists($".\\foo.xlsx"))
{
File.Delete($".\\foo.xlsx");
}
using (var ep = new ExcelPackage(new FileInfo($".\\foo.xlsx")))
{
ExcelWorkbook wb = ep.Workbook;
ExcelWorksheet wsTest = null;
wsTest = wb.Worksheets.Add("Test");
// Add some look up data...
for (int row = 1; row <= 5; row++)
{
wsTest.Cells[row, 1].Value = row;
wsTest.Cells[row, 2].Value = $"Name {row}";
}
wsTest.Cells[1, 4].Formula = $"=XLOOKUP($A3,$A:$A,$B:$B))";
Console.WriteLine($"Add: formula=\"{wsTest.Cells[1, 4].Formula}\"");
Console.WriteLine($"Add: value=\"{wsTest.Cells[1, 4].Value}\"");
ep.Save();
ep.Dispose();
}
using (var ep = new ExcelPackage(new FileInfo($".\\foo.xlsx")))
{
ExcelWorkbook wb = ep.Workbook;
ExcelWorksheet wsTest = null;
wsTest = wb.Worksheets["Test"];
Console.WriteLine($"Open: formula=\"{wsTest.Cells[1, 4].Formula}\"");
Console.WriteLine($"Open: value=\"{wsTest.Cells[1, 4].Value}\"");
ep.Dispose();
}
Console.WriteLine("Test ends");
}
}
}
The output from the above looks like this...
Note that the formula after closing and re-opening the XLSX with EPPLUS reads just as it was written.
However, if I open the file with Excel I can see that an # has been inserted after the = sign.
If I then double click on the formula cell, I get an Excel error message...
I answered "no" to this question because I wanted to continue to experiment with what was happening behind the scenes.
After double clicking the formula cell to edit it, when I now hit ENTER with the # in the formula, it works. At this point I save the XLSX with the change made.
If I now delete some of my code and just run...
using OfficeOpenXml;
using System;
using System.IO;
namespace TestFormula
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Test starts");
ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
using (var ep = new ExcelPackage(new FileInfo($".\\foo.xlsx")))
{
ExcelWorkbook wb = ep.Workbook;
ExcelWorksheet wsTest = null;
wsTest = wb.Worksheets["Test"];
Console.WriteLine($"Open: formula=\"{wsTest.Cells[1, 4].Formula}\"");
Console.WriteLine($"Open: value=\"{wsTest.Cells[1, 4].Value}\"");
ep.Dispose();
}
Console.WriteLine("Test ends");
}
}
}
I get the following output...
What's particularly interesting about the output is that the formula has been modified by Excel and has been prefixed with _alfn.SINGLE.
Research
It is worth declaring here that I am running Microsoft 365 and I always have patches and updates automatically applied as soon as they become available. So my version of Excel is the latest version.
Google-ing for _alfn.SINGLE provides a number of hits (see References below) and from these I have concluded the following:
In Aug 2019 Microsoft released an update that introduced a new formula keyword called XLOOKUP... intended to replace VLOOKUP and HLOOKUP. As such, the XLSX file format was updated to allow for this new feature. The second reference below mentions dates of the introduction of other formulas around Sep 2018.
I'm guessing that the EPLUS library (and probably the openpyxl) have not updated their file format to compensate for the addition of these new/changed features.
When Excel opens an older file version and detects a more recent formula keyword (i.e. a keyword that was not available in the earlier file version), it does not automatically resolve the formula, but instead throws the error I mentioned above, and then resolves the problem by prefixing the new formula keyword with _alfn.SINGLE.
Solution
It's dirty and short term until the EPPLUS/openpyxl libraries catch up. In my case, in code simply replace...
wsTest.Cells[1, 4].Formula = $"=XLOOKUP($A3,$A:$A,$B:$B)";
... with ...
wsTest.Cells[1, 4].Formula = $"_xlfn.SINGLE(_xlfn.XLOOKUP($A3,$A:$A,$B:$B))";
References
Issue: An _xlfn. prefix is displayed in front of a formula by Microsoft
XLOOKUP XMATCH FILTER RANDARRAY SEQUENCE SORT SORTBY UNIQUE CONCAT IFS MAXIFS MINIFS SWITCH TEXTJOIN by Andreas Killer

SyntaxError: Parse error - Wkhtmltopdf with react-pdf-js lib

I am using wkhtmltopdf version 0.12.2.1 (with patched qt) to render my reactJs app! It worked fine, until I added the react-pdf-js lib to render the pdf generated inside my app. I followed the code described on react-pdf-js documentation (see https://www.npmjs.com/package/react-pdf-js) to make it work.
The pdf is rendered inside my page, and it looks pretty cool indeed. But when I try to run wkhtmltopdf again, to generate a pdf of any page of my app, the following error is returned:
desenv01#desenv01-PC:~$ wkhtmltopdf -O Landscape --print-media-type --debug-javascript http://localhost:3000/report/1 report.pdfLoading pages (1/6)
Warning: undefined:0 ReferenceError: Can't find variable: Float64Array
Warning: http://localhost:3000/assets/js/app.js:46789 SyntaxError: Parse error
Counting pages (2/6)
Resolving links (4/6)
Loading headers and footers (5/6)
Printing pages (6/6)
Done
Then, I went to my app.js to see what's on line 46789:
set href(href) {
clear.call(this);
parse.call(this, href);
},
get protocol() {
return this._scheme + ':';
},
set protocol(protocol) {
if (this._isInvalid)
return;
parse.call(this, protocol + ':', 'scheme start');
},
The error happens on the line that says parse.call(this, href);, which is part of pdf.combined.js script.
I could not find any solution online so I wondered if there is anyone who might know if I did something wrong or a way to work around it.
Thanks..
I ran into this using wkthmltopdf 12.3 and 12.4 because I have my IDE set to nag me for using var instead of let. The problem is the older Qt engine powering those versions of the program doesn't recognize new-style, ES6 keywords. Not sure if you can down-convert React. Otherwise you can try the bleeding edge versions which use a newer Qt.
I have same problem. I fixed it by modify some code that i think it is new in JS. let keyword (ES5) and template literals (ES6).
generateRandomColor= function () {
let maxVal = 0xFFFFFF; // 16777215
let randomNumber = Math.random() * maxVal;
randomNumber = Math.floor(randomNumber);
randomNumber = randomNumber.toString(16);
let randColor = randomNumber.padStart(6, 0);
return `#${randColor.toUpperCase()}`
}
I modify above code into below
generateRandomColor = function () {
var maxVal = 0xFFFFFF;
var randomNumber = Math.random() * maxVal;
randomNumber = Math.floor(randomNumber);
randomNumber = randomNumber.toString(16);
var randColor = randomNumber.padStart(6, 0);
return "#" + randColor.toUpperCase();
}

box2d CreateFixture with b2FixtureDef gives pure virtual function call

i have this code that gives me run time error in the line :
body->CreateFixture(&boxDef)
im using cocos2d-x 2.1.5 with box2d 2.2.1 in windows
CCSprite *sprite = CCSprite::create(imageName.c_str());
this->addChild(sprite,1);
b2BodyDef bodyDef;
bodyDef.type = isStatic?b2_staticBody:b2_dynamicBody;
bodyDef.position.Set((position.x+sprite->getContentSize().width/2.0f)/PTM_RATIO,
(position.y+sprite->getContentSize().height/2.0f)/PTM_RATIO);
bodyDef.angle = CC_DEGREES_TO_RADIANS(rotation);
bodyDef.userData = sprite;
b2Body *body = world->CreateBody(&bodyDef);
b2FixtureDef boxDef;
if (isCircle)
{
b2CircleShape circle;
circle.m_radius = sprite->getContentSize().width/2.0f/PTM_RATIO;
boxDef.shape = &circle;
}
else
{
b2PolygonShape box;
box.SetAsBox(sprite->getContentSize().width/2.0f/PTM_RATIO, sprite->getContentSize().height/2.0f/PTM_RATIO);
boxDef.shape = &box;
}
if (isEnemy)
{
boxDef.userData = (void*)1;
enemies->insert(body);
}
boxDef.density = 0.5f;
body->CreateFixture(&boxDef) //<-- HERE IS THE RUN TIME ERROR
;
when i debug the box2d code im getting to b2Fixture.cpp
in the method :
void b2Fixture::Create(b2BlockAllocator* allocator, b2Body* body, const b2FixtureDef* def)
in the line :
m_shape = def->shape->Clone(allocator);
getting the runtime error :
R6025 pure virtual function call
Tricky one. I ran into this myself a couple times. It has to do with variable scope.
The boxDef.shape is the problem. You create the shapes as local variables in the if/else blocks and then assign them to boxDef. As soon as execution leaves the if/else block scope those local variables will be garbage. The boxDef.shape now points to freed memory.
The solution is to keep the shape variables in scope by moving the circle and box shape declarations before the if/else block.

Using GraphView Library for functions to display multiple graphs

I'm currently developing an android app for reading out multiple sensor values via Bluetooth and display them in a graph. When I stumbled upon jjoe64's GraphViewLibrary, I knew this would fit my purposes perfectly. But now I'm kind of stuck. Basically, I wrote a little function that would generate and display the values of three sensors in 3 different graphs one under the other. This works just fine when the activity is started first, all three graphs a nicely rendered and displayed. But when I want to update the graphs with different values using the resetData()-method to render the new values in each graph, only the last of the three graphs is updated. Obviously, because it's the last graph generated using this rather simple function. My question is: Is there any other elegant way to use a function like mine for generating and updating all three graphs one after the other? I already tried to set the GraphView variable back to null and different combinations of removing and adding the view. Passing the function a individual GraphView-variable like graphView1, graphView2... does also not work.
Here is the function:
private GraphView graphView;
private GraphViewSeries graphViewSerie;
private Boolean graphExisting = false;
...
public void makeGraphs (float[] valueArray, String heading, int graphId) {
String graphNumber = "graph"+graphId;
int resId = getResources().getIdentifier(graphNumber,"id", getPackageName());
LinearLayout layout = (LinearLayout) findViewById(resId);
int numElements = valueArray.length;
GraphViewData[] data = new GraphViewData[numElements];
for (int c = 0; c<numElements; c++) {
data[c] = new GraphViewData(c+1, valueArray[c]);
Log.i(tag, "GraphView Graph"+graphId+": ["+(c+1)+"] ["+valueArray[c]+"].");
}
if (!graphExisting) {
// init temperature series data
graphView = new LineGraphView(
this // context
, heading // heading
);
graphViewSerie = new GraphViewSeries(data);
graphView.addSeries(graphViewSerie);
((LineGraphView) graphView).setDrawBackground(true);
graphView.getGraphViewStyle().setNumHorizontalLabels(numElements);
graphView.getGraphViewStyle().setNumVerticalLabels(5);
graphView.getGraphViewStyle().setTextSize(10);
layout.addView(graphView);
}
else {
//graphViewSerie = new GraphViewSeries(data);
//graphViewSerie.resetData(data);
graphViewSerie.resetData(new GraphViewData[] {
new GraphViewData(1, 1.2f)
, new GraphViewData(2, 1.4f)
, new GraphViewData(2.5, 1.5f) // another frequency
, new GraphViewData(3, 1.7f)
, new GraphViewData(4, 1.3f)
, new GraphViewData(5, 1.0f)
});
}
And this is the function-call depending on an previously generated array (which is being monitored to be filled with the right values):
makeGraphs(graphData[0], "TempHistory", 1);
makeGraphs(graphData[1], "AirHistory", 2);
makeGraphs(graphData[2], "SensHistory", 3);
graphExisting = true;
Any help and / or any feedback in general is greatly appreciated! Lots of thanks in advance!
EDIT / UPDATE:
Thanks to jjoe64's answer I was able to modify the function to work properly. I was clearly having a mistake in my thinking, since I thought I'd also be changing a GraphViewSeries-object I would handle my function as additional parameter (which I tried before). Of course this does not work. However, with this minor Improvements I managed to make this work using a Graphviewseries Array. To give people struggling with a similar problem an idea of what I had to change, here the quick-and-dirty draft of the solution.
I just changed
private GraphViewSeries graphViewSerie;
to
private GraphViewSeries graphViewSerie[] = new GraphViewSeries[3];
and access the right Series using the already given parameter graphId within the function (if-clause) like this:
int graphIndex = graphId - 1;
graphViewSerie[graphIndex] = new GraphViewSeries(data);
In the else-clause I'm updating the series likewise by calling
graphViewSerie[graphIndex].resetData(data);
So, once again many thanks for your support, jjoe64. I'm sorry I wasn't able to update the question earlier, but I did not find time for it.
of course it is not working correct, because you save always the latest graphseries-object in the member graphViewSerie.
First you have to store the 3 different graphviewseries (maybe via array or map) and then you have to access the correct graphviewseries-object in the else clause.

QT Phonon on Windows 7

I have to say I'm kinda newbie with QT stuff.
I've tried to get to work Phonom using sample of code:
audioOutput = new Phonon::AudioOutput(Phonon::MusicCategory, this);
mediaObject = new Phonon::MediaObject(this);
metaInformationResolver = new Phonon::MediaObject(this);
Phonon::createPath(mediaObject, audioOutput);
mediaObject->setCurrentSource(Phonon::MediaSource(":/sound/beep.wav"));
mediaObject->play();
The only warning that apears while compilation is:
"WARNING: Phonon::createPath: Cannot connect Phonon::MediaObject ( no objectName ) to Phonon::AudioOutput ( no objectName ). " - it's results with no sound.
I tried to set device output by hand with no results. Meanwhile checked qmediaplayer example - which works fine.
Does anyone can tell me, what I'm doing wrong?
QT += phonon also included
well first of all I'm not sure why you are calling create path() 2 times at line 3 and 5 with same arguments then i'll try setting source before connecting but i don't think this are the real problems
to me this worked:
Phonon::AudioOutput *audioOutput = new Phonon::AudioOutput();
Phonon::MediaObject *mediaObject = new Phonon::MediaObject();
mediaObject->setCurrentSource(Phonon::MediaSource("PathToFile"));
Phonon::createPath(mediaObject, audioOutput);
Phonon::MediaObject *metaInformationResolver = new Phonon::MediaObject();
mediaObject->play();

Resources