更新头像

This commit is contained in:
COMPUTER\EDY 2026-01-28 11:57:05 +08:00
parent 3ce676548c
commit e6a368f9b0
70 changed files with 1753 additions and 678 deletions

View File

@ -142,7 +142,7 @@ export default class JiaZai extends cc.Component {
// } // }
// }); // });
this.createIcon(); // this.createIcon();
cc.fx.GameConfig.GM_INFO.sceneValue = "HomeScene"; cc.fx.GameConfig.GM_INFO.sceneValue = "HomeScene";
@ -388,7 +388,7 @@ export default class JiaZai extends cc.Component {
for (let i = 0; i < iconCount; i++) { for (let i = 0; i < iconCount; i++) {
let iconNode = cc.instantiate(this.icon); let iconNode = cc.instantiate(this.icon);
iconNode.parent = this.node.getChildByName("action"); iconNode.parent = this.node.getChildByName("action");
this.loadSpineSimple(iconNode, "action2"); this.loadSpineSimple(iconNode, "action02");
// 计算每个icon的位置 // 计算每个icon的位置
let position: cc.Vec2; let position: cc.Vec2;
@ -416,79 +416,44 @@ export default class JiaZai extends cc.Component {
} }
} }
// 加载spine动画的完整方法
loadSpineAnimation(node: cc.Node, spinePath: string) {
// 同时加载spine的三个必要文件
cc.resources.loadDir(spinePath, (err: any, assets: any[]) => {
if (err) {
console.error("加载spine资源失败:", err);
return;
}
// 分离不同类型的资源 loadSpineSimple(iconNode: cc.Node, spineName: string) {
let jsonAsset: any = null; // 构建spine资源路径
let atlasAsset: any = null;
let textureAsset: any = null;
assets.forEach(asset => {
if (asset instanceof cc.JsonAsset) {
jsonAsset = asset;
} else if (asset instanceof cc.TextAsset && asset.name.endsWith('.atlas')) {
atlasAsset = asset;
} else if (asset instanceof cc.Texture2D) {
textureAsset = asset;
}
});
if (!jsonAsset || !atlasAsset || !textureAsset) {
console.error("spine资源不完整:", { json: !!jsonAsset, atlas: !!atlasAsset, texture: !!textureAsset });
return;
}
// 创建spine组件
const spine = node.addComponent(sp.Skeleton);
// 设置spine数据
spine.skeletonData = new sp.SkeletonData();
spine.skeletonData.skeletonJson = jsonAsset.json;
spine.skeletonData.atlasText = atlasAsset.text;
spine.skeletonData.textures = [textureAsset];
spine.skeletonData.textureNames = [textureAsset.name];
// 设置默认动画
spine.defaultSkin = "default";
spine.animation = "01"; // 替换为实际的动画名称
spine.loop = true;
// 播放动画
spine.setAnimation(0, "animation", true);
console.log("spine动画加载成功");
});
}
// 或者使用更简单的方法 - 直接加载预配置的spine资源
loadSpineSimple(node: cc.Node, spineName: string) {
// 使用cc.assetManager替换cc.resources.load
const spinePath = `spine/${spineName}/skeleton`; const spinePath = `spine/${spineName}/skeleton`;
cc.assetManager.loadAny(spinePath, sp.SkeletonData, (err: any, skeletonData: sp.SkeletonData) => { // 加载spine资源
cc.resources.load(spinePath, sp.SkeletonData, (err: Error, skeletonData: sp.SkeletonData) => {
if (err) { if (err) {
console.error(`加载spine动画 ${spineName} 失败:`, err); console.error(`加载spine资源失败: ${spinePath}`, err);
return; return;
} }
const spine = node.addComponent(sp.Skeleton); // 检查节点是否已经有spine组件
spine.skeletonData = skeletonData; let spineComponent = iconNode.getComponent(sp.Skeleton);
spine.defaultSkin = "default";
spine.animation = "02"; // 替换为实际的动画名称
spine.loop = true;
spine.setAnimation(0, "02", true);
// console.log(`spine动画 ${spineName} 加载成功`); if (!spineComponent) {
// 如果没有spine组件添加一个
spineComponent = iconNode.addComponent(sp.Skeleton);
}
// 设置skeleton数据
spineComponent.skeletonData = skeletonData;
let actionNumber = "";
if (spineName.startsWith("action")) {
actionNumber = spineName.substring(6); // 提取"action"后面的部分
console.log(`提取的action编号: ${actionNumber}`);
}
spineComponent.setAnimation(0, actionNumber, true);
// 设置spine组件属性
spineComponent.premultipliedAlpha = true;
spineComponent.timeScale = 1.0;
console.log(`成功加载spine动画: ${spineName}`);
}); });
} }
//监听后台 //监听后台
onGames() { onGames() {
//@ts-ignore //@ts-ignore

View File

@ -443,8 +443,8 @@ var GameTool = {
//关卡上限 //关卡上限
maxLevel() { maxLevel() {
let jg = false; let jg = false;
if (cc.fx.GameConfig.GM_INFO.level > 1050) { if (cc.fx.GameConfig.GM_INFO.level > 1049) {
cc.fx.GameConfig.GM_INFO.level = 1051; cc.fx.GameConfig.GM_INFO.level = 1050;
jg = true; jg = true;
} }
return jg; return jg;

File diff suppressed because it is too large Load Diff

View File

@ -19,6 +19,9 @@ export default class CareerItem extends cc.Component {
UI2: cc.SpriteAtlas = null; UI2: cc.SpriteAtlas = null;
randerChildren: any; randerChildren: any;
@property(cc.Prefab)
iconPrefab: cc.Prefab = null;
/**数据改变时调用 */ /**数据改变时调用 */
public dataChanged() { public dataChanged() {
this.randerChildren = []; this.randerChildren = [];
@ -90,12 +93,26 @@ export default class CareerItem extends cc.Component {
this.data.rankingData[i - 4].useravatar == "10" || this.data.rankingData[i - 4].useravatar == "11" || this.data.rankingData[i - 4].useravatar == "12" || this.data.rankingData[i - 4].useravatar == "13" || this.data.rankingData[i - 4].useravatar == "14" this.data.rankingData[i - 4].useravatar == "10" || this.data.rankingData[i - 4].useravatar == "11" || this.data.rankingData[i - 4].useravatar == "12" || this.data.rankingData[i - 4].useravatar == "13" || this.data.rankingData[i - 4].useravatar == "14"
|| this.data.rankingData[i - 4].useravatar == "15" || this.data.rankingData[i - 4].useravatar == "16" || this.data.rankingData[i - 4].useravatar == "17" || this.data.rankingData[i - 4].useravatar == "15" || this.data.rankingData[i - 4].useravatar == "16" || this.data.rankingData[i - 4].useravatar == "17"
) { ) {
this.node.children[i].getChildByName("mask").getChildByName("icon").active = false;
this.node.children[i].getChildByName("mask").getChildByName("sp").active = true;
let useravatar = this.data.rankingData[i - 4].useravatar; let useravatar = this.data.rankingData[i - 4].useravatar;
let useravatarTemp = "icon_" + useravatar; if (this.node.children[i]) {
// console.log("头像名称", useravatarTemp, "用户名字:", username); //this.firstRender.children[i].getChildByName("mask").getChildByName("icon").getComponent(cc.Sprite).spriteFrame = this.UI.getSpriteFrame(useravatarTemp);
this.node.children[i].getChildByName("mask").getChildByName("icon").getComponent(cc.Sprite).spriteFrame = this.UI.getSpriteFrame(useravatarTemp); let actionName = this.getActionName(useravatar);
this.node.children[i].getChildByName("mask").getChildByName("sp").scale = 0.85;
this.loadSpineSimple(this.node.children[i].getChildByName("mask").getChildByName("sp"), actionName);
// this.node.children[i].getChildByName("mask").getChildByName("icon").width = 150;
// this.node.children[i].getChildByName("mask").getChildByName("icon").height = 150;
}
// let useravatar = this.data.rankingData[i - 4].useravatar;
// let useravatarTemp = "icon_" + useravatar;
// this.node.children[i].getChildByName("mask").getChildByName("icon").getComponent(cc.Sprite).spriteFrame = this.UI.getSpriteFrame(useravatarTemp);
}
else {
this.node.children[i].getChildByName("mask").getChildByName("icon").active = true;
this.node.children[i].getChildByName("mask").getChildByName("sp").active = false;
this.setPic(this.data.rankingData[i - 4].useravatar, this.node.children[i].getChildByName("mask").getChildByName("icon"));
} }
else this.setPic(this.data.rankingData[i - 4].useravatar, this.node.children[i].getChildByName("mask").getChildByName("icon"));
} }
} }
} }
@ -105,6 +122,102 @@ export default class CareerItem extends cc.Component {
} }
} }
getActionName(useravatar: string) {
let actionName = "action01";
switch (useravatar) {
case "0":
actionName = "action03";
break;
case "1":
actionName = "action01";
break;
case "2":
actionName = "action09";
break;
case "3":
actionName = "action07";
break;
case "4":
actionName = "action04";
break;
case "5":
actionName = "action04";
break;
case "6":
actionName = "action05";
break;
case "7":
actionName = "action06";
break;
case "8":
actionName = "action02";
break;
case "9":
actionName = "action11";
break;
case "10":
actionName = "action06";
break;
case "11":
actionName = "action15";
break;
case "12":
actionName = "action13";
break;
case "13":
actionName = "action16";
break;
case "14":
actionName = "action06";
break;
case "15":
actionName = "action14";
break;
case "16":
actionName = "action18";
break;
}
return actionName;
}
loadSpineSimple(iconNode: cc.Node, spineName: string) {
// 构建spine资源路径
const spinePath = `spine/${spineName}/skeleton`;
// 加载spine资源
cc.resources.load(spinePath, sp.SkeletonData, (err: Error, skeletonData: sp.SkeletonData) => {
if (err) {
console.error(`加载spine资源失败: ${spinePath}`, err);
return;
}
// 检查节点是否已经有spine组件
let spineComponent = iconNode.getComponent(sp.Skeleton);
if (!spineComponent) {
// 如果没有spine组件添加一个
spineComponent = iconNode.addComponent(sp.Skeleton);
}
// 设置skeleton数据
spineComponent.skeletonData = skeletonData;
let actionNumber = "";
if (spineName.startsWith("action")) {
actionNumber = spineName.substring(6); // 提取"action"后面的部分
}
spineComponent.setAnimation(0, actionNumber, true);
// 设置spine组件属性
spineComponent.premultipliedAlpha = true;
spineComponent.timeScale = 1.0;
});
}
public setPic(url, node) { public setPic(url, node) {
// this.node.getChildByName("pic").getChildByName("icon").active = false; // this.node.getChildByName("pic").getChildByName("icon").active = false;
// this.node.getChildByName("pic").active = false; // this.node.getChildByName("pic").active = false;

View File

@ -128,6 +128,9 @@ export default class CareerList extends cc.Component {
randerChildren: any[]; randerChildren: any[];
topData: any; topData: any;
@property(cc.Prefab)
iconPrefab: cc.Prefab = null;
@property(cc.SpriteAtlas) @property(cc.SpriteAtlas)
UI: cc.SpriteAtlas = null; UI: cc.SpriteAtlas = null;
@ -498,22 +501,126 @@ export default class CareerList extends cc.Component {
let useravatarTemp = "icon_" + useravatar; let useravatarTemp = "icon_" + useravatar;
// console.log("222头像名称", useravatarTemp, "333用户名字:", username); // console.log("222头像名称", useravatarTemp, "333用户名字:", username);
if (this.firstRender.children[i]) { if (this.firstRender.children[i]) {
this.firstRender.children[i].getChildByName("mask").getChildByName("icon").getComponent(cc.Sprite).spriteFrame = this.UI.getSpriteFrame(useravatarTemp); // this.firstRender.children[i].getChildByName("mask").getChildByName("icon").active = false;
//this.firstRender.children[i].getChildByName("mask").getChildByName("icon").getComponent(cc.Sprite).spriteFrame = this.UI.getSpriteFrame(useravatarTemp);
let actionName = this.getActionName(useravatar);
let iconNode = cc.instantiate(this.iconPrefab);
iconNode.parent = this.firstRender.children[i].getChildByName("mask");
iconNode.setPosition(cc.v2(0, 0));
iconNode.width = 150; iconNode.height = 150;
this.loadSpineSimple(iconNode, actionName);
this.firstRender.children[i].getChildByName("mask").getChildByName("icon").width = 150; this.firstRender.children[i].getChildByName("mask").getChildByName("icon").width = 150;
this.firstRender.children[i].getChildByName("mask").getChildByName("icon").height = 150; this.firstRender.children[i].getChildByName("mask").getChildByName("icon").height = 150;
} }
} }
else this.setPic(this.topData[i - 3].useravatar, this.firstRender.children[i].getChildByName("mask").getChildByName("icon")); else {
this.firstRender.children[i].getChildByName("mask").getChildByName("icon").active = true;
this.setPic(this.topData[i - 3].useravatar, this.firstRender.children[i].getChildByName("mask").getChildByName("icon"));
}
} }
} }
} }
} }
}
getActionName(useravatar: string) {
let actionName = "action01";
switch (useravatar) {
case "0":
actionName = "action03";
break;
case "1":
actionName = "action01";
break;
case "2":
actionName = "action09";
break;
case "3":
actionName = "action07";
break;
case "4":
actionName = "action04";
break;
case "5":
actionName = "action04";
break;
case "6":
actionName = "action05";
break;
case "7":
actionName = "action06";
break;
case "8":
actionName = "action02";
break;
case "9":
actionName = "action11";
break;
case "10":
actionName = "action06";
break;
case "11":
actionName = "action15";
break;
case "12":
actionName = "action13";
break;
case "13":
actionName = "action16";
break;
case "14":
actionName = "action06";
break;
case "15":
actionName = "action14";
break;
case "16":
actionName = "action18";
break;
} }
return actionName;
}
loadSpineSimple(iconNode: cc.Node, spineName: string) {
// 构建spine资源路径
const spinePath = `spine/${spineName}/skeleton`;
// 加载spine资源
cc.resources.load(spinePath, sp.SkeletonData, (err: Error, skeletonData: sp.SkeletonData) => {
if (err) {
console.error(`加载spine资源失败: ${spinePath}`, err);
return;
}
// 检查节点是否已经有spine组件
let spineComponent = iconNode.getComponent(sp.Skeleton);
if (!spineComponent) {
// 如果没有spine组件添加一个
spineComponent = iconNode.addComponent(sp.Skeleton);
}
// 设置skeleton数据
spineComponent.skeletonData = skeletonData;
let actionNumber = "";
if (spineName.startsWith("action")) {
actionNumber = spineName.substring(6); // 提取"action"后面的部分
}
spineComponent.setAnimation(0, actionNumber, true);
// 设置spine组件属性
spineComponent.premultipliedAlpha = true;
spineComponent.timeScale = 1.0;
});
}
public setPic(url, node) { public setPic(url, node) {
// this.node.getChildByName("pic").getChildByName("icon").active = false; // this.node.getChildByName("pic").getChildByName("icon").active = false;
// this.node.getChildByName("pic").active = false; // this.node.getChildByName("pic").active = false;

View File

@ -36,8 +36,8 @@
}, },
"_contentSize": { "_contentSize": {
"__type__": "cc.Size", "__type__": "cc.Size",
"width": 170, "width": 180,
"height": 170 "height": 180
}, },
"_anchorPoint": { "_anchorPoint": {
"__type__": "cc.Vec2", "__type__": "cc.Vec2",
@ -74,7 +74,7 @@
"_id": "" "_id": ""
}, },
{ {
"__type__": "cc.Sprite", "__type__": "cc.Mask",
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
@ -86,21 +86,11 @@
"__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432" "__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432"
} }
], ],
"_srcBlendFactor": 770,
"_dstBlendFactor": 771,
"_spriteFrame": null, "_spriteFrame": null,
"_type": 0, "_type": 0,
"_sizeMode": 0, "_segments": 64,
"_fillType": 0, "_N$alphaThreshold": 0.1,
"_fillCenter": { "_N$inverted": false,
"__type__": "cc.Vec2",
"x": 0,
"y": 0
},
"_fillStart": 0,
"_fillRange": 0,
"_isTrimmedMode": true,
"_atlas": null,
"_id": "" "_id": ""
}, },
{ {

View File

@ -1,6 +1,6 @@
{ {
"ver": "1.1.3", "ver": "1.1.3",
"uuid": "ebb76f1b-2e0b-42ff-8437-241bb59df3ce", "uuid": "ac19ca08-99a7-4377-a613-c07dcf12d7c6",
"importer": "folder", "importer": "folder",
"isBundle": false, "isBundle": false,
"bundleName": "", "bundleName": "",

View File

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

View File

@ -1,6 +1,6 @@
{ {
"ver": "1.1.3", "ver": "1.1.3",
"uuid": "6f6f41ed-114a-40da-85ba-64b8f750a4e5", "uuid": "c11043fd-962f-497b-a48b-173fd23a2477",
"importer": "folder", "importer": "folder",
"isBundle": false, "isBundle": false,
"bundleName": "", "bundleName": "",

View File

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

@ -1,6 +1,6 @@
{ {
"ver": "1.1.3", "ver": "1.1.3",
"uuid": "b4552068-8abf-422e-99b9-eed547cb63b4", "uuid": "d0b2a169-e40d-4c07-a5c9-cb31a8f31ecd",
"importer": "folder", "importer": "folder",
"isBundle": false, "isBundle": false,
"bundleName": "", "bundleName": "",

View File

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

@ -1,6 +1,6 @@
{ {
"ver": "1.1.3", "ver": "1.1.3",
"uuid": "b8a9b08c-95ef-4812-b5d5-c0f720c35c8c", "uuid": "2d1a6407-aec5-4403-8cf0-0cf97feb69d4",
"importer": "folder", "importer": "folder",
"isBundle": false, "isBundle": false,
"bundleName": "", "bundleName": "",

View File

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

@ -0,0 +1,13 @@
{
"ver": "1.1.3",
"uuid": "393f8237-353a-4678-9efa-bd8dbe0e0339",
"importer": "folder",
"isBundle": false,
"bundleName": "",
"priority": 1,
"compressionType": {},
"optimizeHotUpdate": {},
"inlineSpriteFrames": {},
"isRemoteBundle": {},
"subMetas": {}
}

View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

@ -0,0 +1,13 @@
{
"ver": "1.1.3",
"uuid": "d18d9343-e152-4073-b3ad-388c27344f84",
"importer": "folder",
"isBundle": false,
"bundleName": "",
"priority": 1,
"compressionType": {},
"optimizeHotUpdate": {},
"inlineSpriteFrames": {},
"isRemoteBundle": {},
"subMetas": {}
}

View File

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 52 KiB

View File

@ -0,0 +1,13 @@
{
"ver": "1.1.3",
"uuid": "a19d3ebd-8d9c-41fe-aa83-af8e701ada24",
"importer": "folder",
"isBundle": false,
"bundleName": "",
"priority": 1,
"compressionType": {},
"optimizeHotUpdate": {},
"inlineSpriteFrames": {},
"isRemoteBundle": {},
"subMetas": {}
}

View File

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

@ -0,0 +1,13 @@
{
"ver": "1.1.3",
"uuid": "a48de90c-8b68-49e4-923b-d8248421f156",
"importer": "folder",
"isBundle": false,
"bundleName": "",
"priority": 1,
"compressionType": {},
"optimizeHotUpdate": {},
"inlineSpriteFrames": {},
"isRemoteBundle": {},
"subMetas": {}
}

View File

@ -0,0 +1 @@
{"skeleton":{"hash":"uTxQEn6GIMpLitxeBIAQuItjefM","spine":"3.8.75","x":-90,"y":-90,"width":180,"height":180,"images":"./09/","audio":"D:/默认头像拆件/01拆件"},"bones":[{"name":"root"}],"slots":[{"name":"80001","bone":"root","attachment":"80007"}],"skins":[{"name":"default","attachments":{"80001":{"80001":{"width":180,"height":180},"80002":{"width":180,"height":180},"80003":{"width":180,"height":180},"80004":{"width":180,"height":180},"80005":{"width":180,"height":180},"80006":{"width":180,"height":180},"80007":{"width":180,"height":180}}}}],"animations":{"09":{"slots":{"80001":{"attachment":[{"name":"80001"},{"time":0.2,"name":"80002"},{"time":0.3,"name":"80003"},{"time":0.4,"name":"80004"},{"time":0.5,"name":"80005"},{"time":0.6,"name":"80006"},{"time":0.7,"name":"80007"},{"time":0.8,"name":"80001"}]}}},"animation":{}}}

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

View File

@ -1,13 +0,0 @@
{
"ver": "1.1.3",
"uuid": "19983066-85a2-48cf-9040-30024602ccdf",
"importer": "folder",
"isBundle": false,
"bundleName": "",
"priority": 1,
"compressionType": {},
"optimizeHotUpdate": {},
"inlineSpriteFrames": {},
"isRemoteBundle": {},
"subMetas": {}
}

View File

@ -1,13 +0,0 @@
{
"ver": "1.1.3",
"uuid": "c056ef3d-6fb0-489c-a92d-6beaf5fcb8b1",
"importer": "folder",
"isBundle": false,
"bundleName": "",
"priority": 1,
"compressionType": {},
"optimizeHotUpdate": {},
"inlineSpriteFrames": {},
"isRemoteBundle": {},
"subMetas": {}
}

View File

@ -1,13 +0,0 @@
{
"ver": "1.1.3",
"uuid": "f44ddb0a-76b4-40c7-ae27-18d5140fa288",
"importer": "folder",
"isBundle": false,
"bundleName": "",
"priority": 1,
"compressionType": {},
"optimizeHotUpdate": {},
"inlineSpriteFrames": {},
"isRemoteBundle": {},
"subMetas": {}
}

View File

@ -1,13 +0,0 @@
{
"ver": "1.1.3",
"uuid": "a5ac1945-1cbb-4fcb-adb5-cb03a46aeec7",
"importer": "folder",
"isBundle": false,
"bundleName": "",
"priority": 1,
"compressionType": {},
"optimizeHotUpdate": {},
"inlineSpriteFrames": {},
"isRemoteBundle": {},
"subMetas": {}
}

View File

@ -1,6 +0,0 @@
{
"ver": "1.0.3",
"uuid": "825913ed-dee8-487b-acdc-43cb9cee4135",
"importer": "asset",
"subMetas": {}
}

View File

@ -1 +0,0 @@
{"skeleton":{"hash":"sYsXXzfp6n/R2ru0AgFZwhXvKRA","spine":"3.8.75","x":-90,"y":-90,"width":180,"height":180,"images":"./09/","audio":""},"bones":[{"name":"root"}],"slots":[{"name":"80001","bone":"root","attachment":"80007"},{"name":"80002","bone":"root"},{"name":"80003","bone":"root"},{"name":"80004","bone":"root"},{"name":"80005","bone":"root"},{"name":"80006","bone":"root"},{"name":"80007","bone":"root"}],"skins":[{"name":"default","attachments":{"80001":{"80001":{"width":180,"height":180},"80002":{"width":180,"height":180},"80003":{"width":180,"height":180},"80004":{"width":180,"height":180},"80005":{"width":180,"height":180},"80006":{"width":180,"height":180},"80007":{"width":180,"height":180}}}}],"animations":{"9":{"slots":{"80001":{"attachment":[{"name":"80001"},{"time":0.2,"name":"80002"},{"time":0.3,"name":"80003"},{"time":0.4,"name":"80004"},{"time":0.5,"name":"80005"},{"time":0.6,"name":"80006"},{"time":0.7,"name":"80007"},{"time":0.8,"name":"80001"}]}}},"animation":{}}}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB